本篇文章主要介绍了深入理解java socket,java中的网络通信是通过socket实现的,socket分为serversocket和socket两大类,有兴趣的可以了解一下
简述
java中socket分为普通socket和niosocket两种,这里介绍socket。
我们可以把socket比作两个城市间的交通工具,有了它可以在两城之间来回穿梭,交通工具有很多种,每种交通工具也有相应的交通规则。socket也一样,也有多种。大多情况下使用的是tcp/ip的流套接字,它是一种稳定的通信协议。(tcp/ip与udp的对比)
java中的网络通信是通过socket实现的,socket分为serversocket和socket两大类,serversocket用于服务端,通过accept方法监听请求,监听到请求后返回socket,socket用于具体完成数据传输,客户端直接使用socket发起请求并传输数据。
serversocket的使用可以分为三步:
1.创建serversocket。serversocket的构造方法一共有5个,通常用的是serversocket(int port),只需要端口号(port)即可。
2.调用创建出来的serversocket的accept方法进行监听。accept方法时阻塞方法,也就是说调用accept方法后程序会停下来等待连接请求,在接收到请求之前程序将不会往下走。当接收到请求后accept方法会返回一个socket。
3.使用accept方法返回的socket与客户端进行通信。
栗子
client:
package io;
import java.io.*;
import java.net.socket;
import java.util.date;
/**
* created by zhengbin06 on 2017/2/2.
*/
public class client {
public static void main(string[] args) {
string msg = "client data";
try {
socket socket = new socket("127.0.0.1", 9090);
// 先写、再读
printwriter printwriter = new printwriter(socket.getoutputstream());
// 发送数据
printwriter.println(msg);
printwriter.flush();
// 获得服务端返回的数据
bufferedreader bufferedreader = new bufferedreader(new inputstreamreader(socket.getinputstream()));
string line = bufferedreader.readline();
system.out.println("received from server: " + line + "\ttime=" + new date().gettime());
// 关闭资源
printwriter.close();
bufferedreader.close();
socket.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
}
server:
package io;
import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.io.printwriter;
import java.net.serversocket;
import java.net.socket;
import java.util.date;
/**
* created by zhengbin06 on 2017/2/2.
*/
public class server {
private static socket socket = null;
private static serversocket serversocket = null;
public static void main(string[] args) throws ioexception {
bufferedreader bufferedreader = null;
printwriter printwriter = null;
try {
// 创建一个serversocket监听9090端口
serversocket = new serversocket(9090);
while (true) {
system.out.println("开始等待请求。。。。");
// 等待请求
// 监听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
socket = serversocket.accept();
system.out.println("接收到请求:" + socket.tostring() + "\ttime=" + new date().gettime());
// 接收到请求后使用socket进行通信, 创建bufferedreader用于读取数据
bufferedreader = new bufferedreader(new inputstreamreader(socket.getinputstream()));
string line = bufferedreader.readline();
system.out.println("received from client: " + line + "\ttime=" + new date().gettime());
// 创建printwriter, 用于发送数据
printwriter = new printwriter(socket.getoutputstream());
printwriter.println("received data: " + line + "\ttime=" + new date().gettime());
printwriter.flush();
}
} finally {
// 关闭所有资源
bufferedreader.close();
printwriter.close();
socket.close();
serversocket.close();
}
}
}
细节
监听请求:
当一个新的socket请求来到时,将为这个连接创建一个新的套接字数据结构,该套接字数据的信息包含的地址和端口正式请求源地址和端口。这个新创建的数据结构将会关联到serversocket实例的一个未完成的连接数据结构列表中。注意,这时服务端的与之对应的socket实例并没有完成创建,而要等到与客户端的3次握手完成后,这个服务端的socket实例才会返回,并将这个socket实例对应的数据结构从未完成列表中移动已完成列表中。
数据传输:
当连接已经建立成功时,服务端和客户端都会拥有一个socket实例,每个socket实例都有一个inputstream和outputstream,并通过这两个对象来交换数据。
要知道网络i/o都是以字节流传输的,当创建socket对象时,操作系统将会为inputstream和outputstream分别分配一定大小的缓存区,数据的写入和读取都是通过这个缓存区完成的。
写入端将数据写到outputstream对应的sendq队列中,当队列填满时,数据将被转移到另一端inputstream的recvq队列中,如果这时recvq已经满了,那么outputstream的write方法将会阻塞,直到recvq队列有足够的空间容纳sendq发送的数据。过程如下图所示:
以上就是深入理解java socket通信的分析的内容。