by shihang.mai
1. BIO:ScoketIO
阻塞IO模型,举例:SocketIOPropertites
服务端
public class SocketIOPropertites {
//server socket listen property:
private static final int RECEIVE_BUFFER = 10;
private static final int SO_TIMEOUT = 0;
private static final boolean REUSE_ADDR = false;
private static final int BACK_LOG = 2;
//client socket listen property on server endpoint:
private static final boolean CLI_KEEPALIVE = false;
private static final boolean CLI_OOB = false;
private static final int CLI_REC_BUF = 20;
private static final boolean CLI_REUSE_ADDR = false;
private static final int CLI_SEND_BUF = 20;
private static final boolean CLI_LINGER = true;
private static final int CLI_LINGER_N = 0;
private static final int CLI_TIMEOUT = 0;
private static final boolean CLI_NO_DELAY = false;
/*
StandardSocketOptions.TCP_NODELAY
StandardSocketOptions.SO_KEEPALIVE
StandardSocketOptions.SO_LINGER
StandardSocketOptions.SO_RCVBUF
StandardSocketOptions.SO_SNDBUF
StandardSocketOptions.SO_REUSEADDR
*/
public static void main(String[] args) {
ServerSocket server = null;
try {
server = new ServerSocket();
server.bind(new InetSocketAddress( 9090), BACK_LOG);
server.setReceiveBufferSize(RECEIVE_BUFFER);
server.setReuseAddress(REUSE_ADDR);
server.setSoTimeout(SO_TIMEOUT);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("server up use 9090!");
while (true) {
try {
System.in.read(); //分水岭:
Socket client = server.accept();
System.out.println("client port: " + client.getPort());
client.setKeepAlive(CLI_KEEPALIVE);
client.setOOBInline(CLI_OOB);
client.setReceiveBufferSize(CLI_REC_BUF);
client.setReuseAddress(CLI_REUSE_ADDR);
client.setSendBufferSize(CLI_SEND_BUF);
client.setSoLinger(CLI_LINGER, CLI_LINGER_N);
client.setSoTimeout(CLI_TIMEOUT);
client.setTcpNoDelay(CLI_NO_DELAY);
new Thread(
() -> {
while (true) {
try {
InputStream in = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
char[] data = new char[1024];
int num = reader.read(data);
if (num > 0) {
System.out.println("client read some data is :" + num + " val :" + new String(data, 0, num));
} else if (num == 0) {
System.out.println("client readed nothing!");
continue;
} else {
System.out.println("client readed -1...");
client.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
).start();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端
public class SocketClient {
public static void main(String[] args) {
try {
Socket client = new Socket("192.168.3.24",9090);
client.setSendBufferSize(20);
client.setTcpNoDelay(false);
client.setOOBInline(false);
OutputStream out = client.getOutputStream();
InputStream in = System.in;
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while(true){
String line = reader.readLine();
if(line != null ){
byte[] bb = line.getBytes();
for (byte b : bb) {
out.write(b);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 过程详解
BIO图解BIO现象过程
- 只启动服务端(ServerSocket没accept)。 出现一个fd代表listen
- 再启动客户端连接服务端,不发消息。客户端和服务端进行3次握手,服务端会出现一个另外fd代表socket连接,但是还没分配进程处理
- 客户端发送消息,socket连接的rev-q有数据
- 服务端accept,socket连接已分配进程处理,并打印了客户端发来的消息
属性 | 位置 | 备注 |
---|---|---|
BACK_LOG | 服务端 | 可连接客户端的个数。当超出个数时,用netstat -natp查看进程时,发现有SYN_RECV状态,即3次握手未成功建立。 |
TcpNoDelay | 客户端 | 设置为fasle时,表明打开优化。一次性发送大于设置SendBufferSize的值,会一次性发送所有的消息,并不会受SendBufferSize约束。 |
CLI_KEEPALIVE | 服务端 | 服务端-客户端自动保持心跳 |
系统调用过程
- 调用socket()返回一个fd
- 调用bind(fd,9090),将fd和端口绑定起来
- 调用listen(),监听端口
- 调用accept(),会产生一个新fd而且会标注为blocking的
- 调用recv(新fd),也是标注为blocking的
3. BIO弊端
它accept和receive都是阻塞的.当我们accept后,开启线程去处理,每个连接均需要调用内核的clone()去创建线程
BIO弊端
网友评论