// Check if the datagramsocket adaptor can send with a packet // that has not been initialized with an address; the legacy // datagram socket will send in this case private static void test2() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); byte b[] = "hello".getBytes("UTF-8"); DatagramPacket pkt = new DatagramPacket(b, b.length); sndChannel.socket().send(pkt); ByteBuffer bb = ByteBuffer.allocate(256); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); // Check that the pkt got set with the target address; // This is legacy behavior if (!pkt.getSocketAddress().equals(receiver)) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
// Check if DatagramChannel.send while connected can include // address without throwing private static void test1() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); ByteBuffer bb = ByteBuffer.allocate(256); bb.put("hello".getBytes()); bb.flip(); int sent = sndChannel.send(bb, receiver); bb.clear(); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
private void recv(SocketChannel sc, ClientInfo ci) throws IOException { ci.channel.read(ci.inBuf); ByteBuffer tmpBuf = ci.inBuf.duplicate(); tmpBuf.flip(); int bytesProcessed = 0; boolean doneLoop = false; while (!doneLoop) { byte b; try { b = tmpBuf.get(); } catch (BufferUnderflowException bue) { // Processed all data in buffer ci.inBuf.clear(); doneLoop = true; break; } switch (b) { case TypeServerConstants.WELCOME: bytesProcessed++; break; case TypeServerConstants.GET_STRING_REQUEST: bytesProcessed++; if (ci.outputPending) { // Client is backed up. We can't append to // the byte buffer because it's in the wrong // state. We could allocate another buffer // here and change our send method to know // about multiple buffers, but we'll just // assume that the client is dead break; } ci.outBuf.put(TypeServerConstants.GET_STRING_RESPONSE); ByteBuffer strBuf = encoder.encode(testString); ci.outBuf.putShort((short) strBuf.remaining()); ci.outBuf.put(strBuf); ci.outBuf.flip(); send(sc, ci); break; case TypeServerConstants.GET_STRING_RESPONSE: int startPos = tmpBuf.position(); try { int nBytes = tmpBuf.getInt(); byte[] buf = new byte[nBytes]; tmpBuf.get(buf); bytesProcessed += buf.length + 5; String s = new String(buf); // Send the string to the GUI break; } catch (BufferUnderflowException bue) { // Processed all available data ci.inBuf.position(ci.inBuf.position() + bytesProcessed); doneLoop = true; } break; } } }
/** * Tests response handling with specified charset in the header 'Content-Type'. * * @throws IOException I/O Exception * @throws QueryException query exception */ @Test public void responseWithCharset() throws IOException, QueryException { // Create fake HTTP connection final FakeHttpConnection conn = new FakeHttpConnection(new URL("http://www.test.com")); // Set content type conn.contentType = "text/plain; charset=CP1251"; // set content encoded in CP1251 final String test = "\u0442\u0435\u0441\u0442"; conn.content = Charset.forName("CP1251").encode(test).array(); final ItemList res = new HttpResponse(null, ctx.options).getResponse(conn, true, null); // compare results assertEquals(test, string(res.get(1).string(null))); }
/** * Decode file charset. * * @param f File to process. * @return File charset. * @throws IOException in case of error. */ public static Charset decode(File f) throws IOException { SortedMap<String, Charset> charsets = Charset.availableCharsets(); String[] firstCharsets = { Charset.defaultCharset().name(), "US-ASCII", "UTF-8", "UTF-16BE", "UTF-16LE" }; Collection<Charset> orderedCharsets = U.newLinkedHashSet(charsets.size()); for (String c : firstCharsets) if (charsets.containsKey(c)) orderedCharsets.add(charsets.get(c)); orderedCharsets.addAll(charsets.values()); try (RandomAccessFile raf = new RandomAccessFile(f, "r")) { FileChannel ch = raf.getChannel(); ByteBuffer buf = ByteBuffer.allocate(4096); ch.read(buf); buf.flip(); for (Charset charset : orderedCharsets) { CharsetDecoder decoder = charset.newDecoder(); decoder.reset(); try { decoder.decode(buf); return charset; } catch (CharacterCodingException ignored) { } } } return Charset.defaultCharset(); }
/** * Returns the connection charset. Defaults to {@link Charset} defaultCharset if not set * * @return charset */ public String getCharset() { return charset == null ? Charset.defaultCharset().name() : charset; }
// 感觉如果没有看过 NIO 的详细内容是不会懂这部分 public class TypeServer extends TCPNIOServer { static String testString = "Thisisateststring"; static class ClientInfo { ByteBuffer inBuf = ByteBuffer.allocateDirect(512); ByteBuffer outBuf = ByteBuffer.allocateDirect(512); boolean outputPending = false; SocketChannel channel; } Map allClients = new HashMap(); Charset encoder = Charset.forName("UTF-8"); protected void handleClient(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel(); ClientInfo ci = (ClientInfo) allClients.get(sc); if (ci == null) throw new IllegalStateException("Unknown client"); if (key.isWritable()) send(sc, ci); if (key.isReadable()) // 从一个客户端读进所有的可用数据 recv(sc, ci); } private void recv(SocketChannel sc, ClientInfo ci) throws IOException { ci.channel.read(ci.inBuf); ByteBuffer tmpBuf = ci.inBuf.duplicate(); tmpBuf.flip(); int bytesProcessed = 0; boolean doneLoop = false; while (!doneLoop) { byte b; try { b = tmpBuf.get(); } catch (BufferUnderflowException bue) { // Processed all data in buffer ci.inBuf.clear(); doneLoop = true; break; } switch (b) { case TypeServerConstants.WELCOME: bytesProcessed++; break; case TypeServerConstants.GET_STRING_REQUEST: bytesProcessed++; if (ci.outputPending) { // Client is backed up. We can't append to // the byte buffer because it's in the wrong // state. We could allocate another buffer // here and change our send method to know // about multiple buffers, but we'll just // assume that the client is dead break; } ci.outBuf.put(TypeServerConstants.GET_STRING_RESPONSE); ByteBuffer strBuf = encoder.encode(testString); ci.outBuf.putShort((short) strBuf.remaining()); ci.outBuf.put(strBuf); ci.outBuf.flip(); send(sc, ci); break; case TypeServerConstants.GET_STRING_RESPONSE: int startPos = tmpBuf.position(); try { int nBytes = tmpBuf.getInt(); byte[] buf = new byte[nBytes]; tmpBuf.get(buf); bytesProcessed += buf.length + 5; String s = new String(buf); // Send the string to the GUI break; } catch (BufferUnderflowException bue) { // Processed all available data ci.inBuf.position(ci.inBuf.position() + bytesProcessed); doneLoop = true; } break; } } } private void send(SocketChannel sc, ClientInfo ci) throws IOException { int len = ci.outBuf.remaining(); int nBytes = sc.write(ci.outBuf); if (nBytes != len) { // Client not ready to receive data ci.outputPending = true; ci.channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } else { ci.outBuf.clear(); if (ci.outputPending) { ci.outputPending = false; ci.channel.register(selector, SelectionKey.OP_READ); } } } protected void registeredClient(SocketChannel sc) throws IOException { ClientInfo ci = new ClientInfo(); ci.channel = sc; ci.outBuf.clear(); ci.outBuf.put(TypeServerConstants.WELCOME); ci.outBuf.flip(); allClients.put(sc, ci); send(sc, ci); } public static void main(String[] args) throws Exception { TypeServer ts = new TypeServer(); ts.port = Integer.parseInt(args[0]); Thread t = new Thread(ts); t.start(); System.out.println("Type server ready...Type CTRL-D to exit"); while (System.in.read() > 0) ; ts.stopServer(); t.join(); } }
/** * Java client for BaseX. Works with BaseX 7.0 and later * * <p>Documentation: http://docs.basex.org/wiki/Clients * * <p>(C) BaseX Team 2005-12, BSD License */ public class BaseXClient { /** UTF-8 charset. */ static final Charset UTF8 = Charset.forName("UTF-8"); /** Event notifications. */ final Map<String, EventNotifier> notifiers = new HashMap<String, EventNotifier>(); /** Output stream. */ final OutputStream out; /** Socket. */ final Socket socket; /** Cache. */ final BufferedInputStream in; /** Command info. */ String info; /** Socket event reference. */ Socket esocket; /** Socket host name. */ String ehost; /** * Constructor. * * @param host server name * @param port server port * @param user user name * @param pass password * @throws IOException Exception */ public BaseXClient(final String host, final int port, final String user, final String pass) throws IOException { socket = new Socket(); socket.connect(new InetSocketAddress(host, port), 5000); in = new BufferedInputStream(socket.getInputStream()); out = socket.getOutputStream(); ehost = host; // receive timestamp final String ts = receive(); // send {Username}0 and hashed {Password/Timestamp}0 send(user); send(md5(md5(pass) + ts)); // receive success flag if (!ok()) throw new IOException("Access denied."); } /** * Executes a command and serializes the result to an output stream. * * @param cmd command * @param o output stream * @throws IOException Exception */ public void execute(final String cmd, final OutputStream o) throws IOException { // send {Command}0 send(cmd); receive(in, o); info = receive(); if (!ok()) throw new IOException(info); } /** * Executes a command and returns the result. * * @param cmd command * @return result * @throws IOException Exception */ public String execute(final String cmd) throws IOException { final ByteArrayOutputStream os = new ByteArrayOutputStream(); execute(cmd, os); return new String(os.toByteArray(), UTF8); } /** * Creates a query object. * * @param query query string * @return query * @throws IOException Exception */ public Query query(final String query) throws IOException { return new Query(query); } /** * Creates a database. * * @param name name of database * @param input xml input * @throws IOException I/O exception */ public void create(final String name, final InputStream input) throws IOException { send(8, name, input); } /** * Adds a document to a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void add(final String path, final InputStream input) throws IOException { send(9, path, input); } /** * Replaces a document in a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void replace(final String path, final InputStream input) throws IOException { send(12, path, input); } /** * Stores a binary resource in a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void store(final String path, final InputStream input) throws IOException { send(13, path, input); } /** * Watches an event. * * @param name event name * @param notifier event notification * @throws IOException I/O exception */ public void watch(final String name, final EventNotifier notifier) throws IOException { out.write(10); if (esocket == null) { final int eport = Integer.parseInt(receive()); // initialize event socket esocket = new Socket(); esocket.connect(new InetSocketAddress(ehost, eport), 5000); final OutputStream os = esocket.getOutputStream(); receive(in, os); os.write(0); os.flush(); final InputStream is = esocket.getInputStream(); is.read(); listen(is); } send(name); info = receive(); if (!ok()) throw new IOException(info); notifiers.put(name, notifier); } /** * Unwatches an event. * * @param name event name * @throws IOException I/O exception */ public void unwatch(final String name) throws IOException { out.write(11); send(name); info = receive(); if (!ok()) throw new IOException(info); notifiers.remove(name); } /** * Returns command information. * * @return string info */ public String info() { return info; } /** * Closes the session. * * @throws IOException Exception */ public void close() throws IOException { send("exit"); out.flush(); if (esocket != null) esocket.close(); socket.close(); } /** * Checks the next success flag. * * @return value of check * @throws IOException Exception */ boolean ok() throws IOException { out.flush(); return in.read() == 0; } /** * Returns the next received string. * * @return String result or info * @throws IOException I/O exception */ String receive() throws IOException { final ByteArrayOutputStream os = new ByteArrayOutputStream(); receive(in, os); return new String(os.toByteArray(), UTF8); } /** * Sends a string to the server. * * @param s string to be sent * @throws IOException I/O exception */ void send(final String s) throws IOException { out.write((s + '\0').getBytes(UTF8)); } /** * Receives a string and writes it to the specified output stream. * * @param is input stream * @param os output stream * @throws IOException I/O exception */ static void receive(final InputStream is, final OutputStream os) throws IOException { for (int b; (b = is.read()) > 0; ) { // read next byte if 0xFF is received os.write(b == 0xFF ? is.read() : b); } } /** * Sends a command, argument, and input. * * @param cmd command * @param path path to document * @param input xml input * @throws IOException I/O exception */ private void send(final int cmd, final String path, final InputStream input) throws IOException { out.write(cmd); send(path); send(input); } /** * Starts the listener thread. * * @param is input stream */ private void listen(final InputStream is) { final BufferedInputStream bi = new BufferedInputStream(is); new Thread() { @Override public void run() { try { while (true) { ByteArrayOutputStream os = new ByteArrayOutputStream(); receive(bi, os); final String name = new String(os.toByteArray(), UTF8); os = new ByteArrayOutputStream(); receive(bi, os); final String data = new String(os.toByteArray(), UTF8); notifiers.get(name).notify(data); } } catch (final IOException ex) { // loop will be quit if no data can be received anymore } } }.start(); } /** * Sends an input stream to the server. * * @param input xml input * @throws IOException I/O exception */ private void send(final InputStream input) throws IOException { final BufferedInputStream bis = new BufferedInputStream(input); final BufferedOutputStream bos = new BufferedOutputStream(out); for (int b; (b = bis.read()) != -1; ) { // 0x00 and 0xFF will be prefixed by 0xFF if (b == 0x00 || b == 0xFF) bos.write(0xFF); bos.write(b); } bos.write(0); bos.flush(); info = receive(); if (!ok()) throw new IOException(info); } /** * Returns an MD5 hash. * * @param pw String * @return String */ private static String md5(final String pw) { final StringBuilder sb = new StringBuilder(); try { final MessageDigest md = MessageDigest.getInstance("MD5"); md.update(pw.getBytes()); for (final byte b : md.digest()) { final String s = Integer.toHexString(b & 0xFF); if (s.length() == 1) sb.append('0'); sb.append(s); } } catch (final NoSuchAlgorithmException ex) { // should not occur ex.printStackTrace(); } return sb.toString(); } /** Inner class for iterative query execution. */ public class Query { /** Query id. */ private final String id; /** Cached results. */ private ArrayList<byte[]> cache; /** Cache pointer. */ private int pos; /** * Standard constructor. * * @param query query string * @throws IOException I/O exception */ public Query(final String query) throws IOException { id = exec(0, query); } /** * Binds a value to an external variable. * * @param name name of variable * @param value value * @throws IOException I/O exception */ public void bind(final String name, final String value) throws IOException { bind(name, value, ""); } /** * Binds a value with the specified type to an external variable. * * @param name name of variable * @param value value * @param type type (can be an empty string) * @throws IOException I/O exception */ public void bind(final String name, final String value, final String type) throws IOException { cache = null; exec(3, id + '\0' + name + '\0' + value + '\0' + type); } /** * Binds a value to the context item. * * @param value value * @throws IOException I/O exception */ public void context(final String value) throws IOException { context(value, ""); } /** * Binds a value with the specified type to the context item. * * @param value value * @param type type (can be an empty string) * @throws IOException I/O exception */ public void context(final String value, final String type) throws IOException { cache = null; exec(14, id + '\0' + value + '\0' + type); } /** * Checks for the next item. * * @return result of check * @throws IOException I/O exception */ public boolean more() throws IOException { if (cache == null) { out.write(4); send(id); cache = new ArrayList<byte[]>(); final ByteArrayOutputStream os = new ByteArrayOutputStream(); while (in.read() > 0) { receive(in, os); cache.add(os.toByteArray()); os.reset(); } if (!ok()) throw new IOException(receive()); pos = 0; } if (pos < cache.size()) return true; cache = null; return false; } /** * Returns the next item. * * @return item string * @throws IOException I/O Exception */ public String next() throws IOException { return more() ? new String(cache.set(pos++, null), UTF8) : null; } /** * Returns the whole result of the query. * * @return query result * @throws IOException I/O Exception */ public String execute() throws IOException { return exec(5, id); } /** * Returns query info in a string. * * @return query info * @throws IOException I/O exception */ public String info() throws IOException { return exec(6, id); } /** * Returns serialization parameters in a string. * * @return query info * @throws IOException I/O exception */ public String options() throws IOException { return exec(7, id); } /** * Closes the query. * * @throws IOException I/O exception */ public void close() throws IOException { exec(2, id); } /** * Executes the specified command. * * @param cmd command * @param arg argument * @return resulting string * @throws IOException I/O exception */ private String exec(final int cmd, final String arg) throws IOException { out.write(cmd); send(arg); final String s = receive(); if (!ok()) throw new IOException(receive()); return s; } } /** Interface for event notifications. */ public interface EventNotifier { /** * Invoked when a database event was fired. * * @param value event string */ void notify(final String value); } }