Socket用法
/**
* 通过Java socket获取www.baidu.com首页内容
*/
Socket s = new Socket("www.baidu.com", 80);
Scanner scanner = null;
OutputStreamWriter osw = null;
try {
scanner = new Scanner(s.getInputStream());
osw = new OutputStreamWriter(s.getOutputStream());
//两个回车, 使用 HTTP/1.1 的话会保持长链接
osw.write("GET / HTTP/1.0\r\n\r\n");
osw.flush(); //需要flush 否则可能数据没发出去
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
safeClose(s);
}
ServerSocket用法
private static void genSingleServer(int port) {
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
Socket incoming = ss.accept();
Scanner scanner = null;
PrintWriter pw = null;
try {
scanner = new Scanner(incoming.getInputStream());
pw = new PrintWriter(incoming.getOutputStream());
while (scanner.hasNext()) {
String line = scanner.nextLine();
if ("exit".equals(line)) {
pw.println("Bye");
pw.flush();
break;
}
pw.println(line);
pw.flush();
}
} finally {
safeClose(scanner);
safeClose(pw);
safeClose(incoming);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
safeClose(ss);
}
}
image.png
当连接已经建立成功,服务端和客户端都会拥有一个 Socket 实例,每个 Socket 实例都有一个 InputStream 和 OutputStream,正是通过这两个对象来交换数据。同时我们也知道网络 I/O 都是以字节流传输的。当 Socket 对象创建时,操作系统将会为 InputStream 和 OutputStream 分别分配一定大小的缓冲区,数据的写入和读取都是通过这个缓存区完成的。写入端将数据写到 OutputStream 对应的 SendQ 队列中,当队列填满时,数据将被发送到另一端 InputStream 的 RecvQ 队列中,如果这时 RecvQ 已经满了,那么 OutputStream 的 write 方法将会阻塞直到 RecvQ 队列有足够的空间容纳 SendQ 发送的数据。值得特别注意的是,这个缓存区的大小以及写入端的速度和读取端的速度非常影响这个连接的数据传输效率,由于可能会发生阻塞,所以网络 I/O 与磁盘 I/O 在数据的写入和读取还要有一个协调的过程,如果两边同时传送数据时可能会产生死锁,在后面 NIO 部分将介绍避免这种情况。
网友评论