这里写目录标题
需要用到的命令
lsof -p
netstat -natp
tcpdump
jps // java-1.8.0-openjdk-devel
代码
server代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
public class SocketBioDemo {
// 参数
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;
// 通讯中的参数
// 长链接
private static final boolean _KEEPALIVE = false;
// 是否优先发一个字符做嗅探
private static final boolean _OOB = false;
// netstat -natp 查看receive q 相关
private static final int _REC_BUF = 20;
// 是否重定向地址
private static final boolean _REUSE_ADDR = false;
// send buffer
private static final int _SEND_BUF = 20;
// 断开连接的速度
private static final boolean _LINGER = true;
//???
private static final int _LINGER_N = 0;
// 读取的时候 超时时间 等client多久
private static final int _TIMEOUT = 0;
// tcp优化算法 发送数据比较少可以缓冲
private static final boolean _NO_DELAY = false;
public static void main(String[] args) {
System.out.println("server");
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(11111), BACK_LOG);
serverSocket.setReceiveBufferSize(RECEIVE_BUFFER);
serverSocket.setReuseAddress(REUSE_ADDR);
serverSocket.setSoTimeout(SO_TIMEOUT);
while (true){
try {
System.in.read();
Socket client = serverSocket.accept();
System.out.println("client:" + client.getPort());
client.setKeepAlive(_KEEPALIVE);
client.setOOBInline(_OOB);
client.setReceiveBufferSize(_REC_BUF);
client.setReuseAddress(_REUSE_ADDR);
client.setSendBufferSize(_SEND_BUF);
client.setSoLinger(_LINGER, _LINGER_N);
client.setSoTimeout(_TIMEOUT);
client.setTcpNoDelay(_NO_DELAY);
new Thread(() -> {
while (true) {
InputStream in = null;
try {
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("data:" + num + "," + new String(data, 0, num));
}else if(num==0){
}else{
System.out.println("close");
client.close();
break;
}
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}).start();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
}catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
client代码(ip自己确定一下是同一个机器还是两台机器)
import java.io.*;
import java.net.Socket;
public class SocketBioClient {
public static void main(String[] args) {
System.out.println("start");
try {
Socket client = new Socket("<ip>",11111);
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();
System.out.println("read:"+line);
if(line!=null){
byte[] bb = line.getBytes();
for (byte b :bb){
out.write(b);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
server启动
启动server
java Server
查看网络
netstat -natp
这时候你大概能看到这样的东西
这时候用jps查看下,获取到这个server的文件标识符
jps
lsof -p 21154
这一整个,就是当前server启动的记录了
启动抓包窗口
// 由于client启动的时候会发出消息,这里要先启动抓包,ifconfig 查一下自己的网卡,然后替换掉<NETWORK>
tcpdump -nn -i <NETWORK> port 11111
// 例如
tcpdump -nn -i ens3 port 11111
// 如果是同一台机器,client的ip是127.0.0.1,那就要监听lo了 例如
tcpdump -nn -i lo port 11111
client启动
java Client
开始查看抓包内容
启动内容
20:10:48.740386 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [S], seq 3826206646, win 43690, options [mss 65495,sackOK,TS val 976498522 ecr 0,nop,wscale 7], length 0
20:10:48.740410 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [S.], seq 2352561994, ack 3826206647, win 1152, options [mss 65495,sackOK,TS val 976498522 ecr 976498522,nop,wscale 0], length 0
20:10:48.740430 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [.], ack 1, win 342, options [nop,nop,TS val 976498522 ecr 976498522], length 0
这就是http三次握手的具体内容,具体自行查阅seq ack等
这时候再次查看网络
netstat -natp
之前就看到的listen
这里的第二个是代表内核态已经有了这个,但是目前没有分配给任何程序处理,前面的recv-q 和send-q 都是0,没有任何数据堆积
一个是client链接server
Client发起数据
// 例如
hello
这时候查看抓包
20:10:48.740386 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [S], seq 3826206646, win 43690, options [mss 65495,sackOK,TS val 976498522 ecr 0,nop,wscale 7], length 0
20:10:48.740410 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [S.], seq 2352561994, ack 3826206647, win 1152, options [mss 65495,sackOK,TS val 976498522 ecr 976498522,nop,wscale 0], length 0
20:10:48.740430 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [.], ack 1, win 342, options [nop,nop,TS val 976498522 ecr 976498522], length 0
20:24:14.408096 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 1:2, ack 1, win 342, options [nop,nop,TS val 977304190 ecr 976498522], length 1
20:24:14.408152 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 2, win 1151, options [nop,nop,TS val 977304190 ecr 977304190], length 0
20:24:14.408221 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 2:3, ack 1, win 342, options [nop,nop,TS val 977304190 ecr 977304190], length 1
20:24:14.448105 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 3, win 1150, options [nop,nop,TS val 977304230 ecr 977304190], length 0
20:24:14.448187 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 3:6, ack 1, win 342, options [nop,nop,TS val 977304230 ecr 977304230], length 3
20:24:14.488099 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 6, win 1147, options [nop,nop,TS val 977304270 ecr 977304230], length 0
因为Server的参数设置,所以hello 分三次 h e llo 看到后面的length可以看的出来
再次查看网络
netstat -natp
这里棉的recv-q,已经变成了5 已经有数据了,但是仍旧没有程序处理
Server 接收数据
取消Server的阻塞
敲一下回车,这时候就不阻塞了,我们看到client发来的消息
####查看网络
netstat -natp
已经没有阻塞的数据了,后面也有标识,java开始处理
再次lsof查看
// jps获取文件标识符
jps
// lsof 查看状态
lsof -p 18148
四次挥手
20:10:48.740386 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [S], seq 3826206646, win 43690, options [mss 65495,sackOK,TS val 976498522 ecr 0,nop,wscale 7], length 0
20:10:48.740410 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [S.], seq 2352561994, ack 3826206647, win 1152, options [mss 65495,sackOK,TS val 976498522 ecr 976498522,nop,wscale 0], length 0
20:10:48.740430 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [.], ack 1, win 342, options [nop,nop,TS val 976498522 ecr 976498522], length 0
20:24:14.408096 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 1:2, ack 1, win 342, options [nop,nop,TS val 977304190 ecr 976498522], length 1
20:24:14.408152 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 2, win 1151, options [nop,nop,TS val 977304190 ecr 977304190], length 0
20:24:14.408221 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 2:3, ack 1, win 342, options [nop,nop,TS val 977304190 ecr 977304190], length 1
20:24:14.448105 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 3, win 1150, options [nop,nop,TS val 977304230 ecr 977304190], length 0
20:24:14.448187 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [P.], seq 3:6, ack 1, win 342, options [nop,nop,TS val 977304230 ecr 977304230], length 3
20:24:14.488099 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [.], ack 6, win 1147, options [nop,nop,TS val 977304270 ecr 977304230], length 0
20:48:19.676947 IP 192.168.31.151.54188 > 192.168.31.151.11111: Flags [F.], seq 6, ack 1, win 342, options [nop,nop,TS val 978749458 ecr 977304270], length 0
20:48:19.678164 IP 192.168.31.151.11111 > 192.168.31.151.54188: Flags [R.], seq 1, ack 7, win 1147, options [nop,nop,TS val 978749460 ecr 978749458], length 0
如果你看懂了以上的内容,那么,为什么握手三次即可,但是挥手却要四次,抓包为什么只看到了新增两行信息而不是四行
总结
额外
拥塞机制
在上文中搜索win,即可看到win的数值,win是互相通知win的大小,如果server的win过小,客户端回自己阻塞
抓包查看
- 启动server保持阻塞状态
- 启动client不停的输入
- 查看抓包
20:55:37.852720 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [S], seq 1721479900, win 43690, options [mss 65495,sackOK,TS val 979187634 ecr 0,nop,wscale 7], length 0
20:55:37.852739 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [S.], seq 3727003628, ack 1721479901, win 1152, options [mss 65495,sackOK,TS val 979187634 ecr 979187634,nop,wscale 0], length 0
20:55:37.852753 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [.], ack 1, win 342, options [nop,nop,TS val 979187634 ecr 979187634], length 0
20:55:43.949972 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 1:2, ack 1, win 342, options [nop,nop,TS val 979193731 ecr 979187634], length 1
20:55:43.949987 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 2, win 1151, options [nop,nop,TS val 979193731 ecr 979193731], length 0
20:55:43.950045 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 2:3, ack 1, win 342, options [nop,nop,TS val 979193732 ecr 979193731], length 1
20:55:43.990076 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 3, win 1150, options [nop,nop,TS val 979193772 ecr 979193732], length 0
20:55:43.990112 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 3:75, ack 1, win 342, options [nop,nop,TS val 979193772 ecr 979193772], length 72
20:55:44.030063 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 75, win 1078, options [nop,nop,TS val 979193812 ecr 979193772], length 0
20:55:48.418981 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 75:76, ack 1, win 342, options [nop,nop,TS val 979198200 ecr 979193812], length 1
20:55:48.419026 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 76, win 1077, options [nop,nop,TS val 979198200 ecr 979198200], length 0
20:55:48.419063 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 76:77, ack 1, win 342, options [nop,nop,TS val 979198201 ecr 979198200], length 1
20:55:48.459076 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 77, win 1076, options [nop,nop,TS val 979198241 ecr 979198201], length 0
20:55:48.459104 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 77:156, ack 1, win 342, options [nop,nop,TS val 979198241 ecr 979198241], length 79
20:55:48.499079 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 156, win 997, options [nop,nop,TS val 979198281 ecr 979198241], length 0
20:55:53.954209 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 156:157, ack 1, win 342, options [nop,nop,TS val 979203736 ecr 979198281], length 1
20:55:53.954222 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 157, win 996, options [nop,nop,TS val 979203736 ecr 979203736], length 0
20:55:53.954237 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 157:158, ack 1, win 342, options [nop,nop,TS val 979203736 ecr 979203736], length 1
20:55:53.994042 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 158, win 995, options [nop,nop,TS val 979203776 ecr 979203736], length 0
20:55:53.994056 IP 192.168.31.151.40218 > 192.168.31.151.11111: Flags [P.], seq 158:238, ack 1, win 342, options [nop,nop,TS val 979203776 ecr 979203776], length 80
20:55:54.034072 IP 192.168.31.151.11111 > 192.168.31.151.40218: Flags [.], ack 238, win 915, options [nop,nop,TS val 979203816 ecr 979203776], length 0
这样就可以看出server测的win是逐渐变小的