use std::io::prelude::*;
use std::net::TcpStream;
use std::thread;
fnmain() {
letmut stream = TcpStream::connect("192.168.2.229:33333").unwrap();
let n = stream.write(&[1,2,3,4,5,6,7,8,9]).unwrap();
println!("send {} bytes to remote node, waiting for end.", n);
loop{
thread::sleep_ms(1000);
}
}
/* Structure used to manipulate the SO_LINGER option. */structlinger
{int l_onoff; /* Nonzero to linger on close. */int l_linger; /* Time to linger. */
};
/* echo server with poll */#include<poll.h>#include<stdio.h>#include<stdlib.h>#include<arpa/inet.h>#include<netinet/in.h>#include<sys/socket.h>#include<sys/types.h>#include<unistd.h>#include<string.h>#include<fcntl.h>#include<errno.h>#include<pthread.h>#define OPEN_MAX 1024#define LISTEN_PORT 33333#define MAX_BUF 1024intset_linger(int sock, int l_onoff, int l_linger);
inthandle_conn(struct pollfd *nfds, char* buf);
voidrun();
intmain(int _argc, char* _argv[]){
run();
return0;
}
voidrun(){
// bind socketchar str[INET_ADDRSTRLEN];
structsockaddr_inseraddr, cliaddr;socklen_t cliaddr_len = sizeof(cliaddr);
int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
bzero(&seraddr, sizeof(seraddr));
seraddr.sin_family = AF_INET;
seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
seraddr.sin_port = htons(LISTEN_PORT);
int opt = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (-1 == bind(listen_sock, (struct sockaddr*)&seraddr, sizeof(seraddr))) {
perror("bind server addr failure.");
exit(EXIT_FAILURE);
}
listen(listen_sock, 5);
int ret, i;
structpollfdnfds[OPEN_MAX];for (i=0;i<OPEN_MAX;++i){
nfds[i].fd = -1;
}
nfds[0].fd = listen_sock;
nfds[0].events = POLLIN;
char* buf = (char*)malloc(MAX_BUF);
while (1) {
ret = poll(nfds, OPEN_MAX, NULL);
if (-1 == ret) {
perror("poll failure.");
exit(EXIT_FAILURE);
}
/* An event on one of the fds has occurred. */if (nfds[0].revents & POLLIN) {
int conn_sock = accept(listen_sock, (struct sockaddr *)&cliaddr, &cliaddr_len);
if (-1 == conn_sock) {
perror("accept failure.");
exit(EXIT_FAILURE);
}
printf("accept from %s:%d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
set_linger(conn_sock, 1, 0); //设置SO_LINGER option值为0for (int k=0;k<OPEN_MAX;++k){
if (nfds[k].fd < 0){
nfds[k].fd = conn_sock;
nfds[k].events = POLLIN;
break;
}
if (k == OPEN_MAX-1){
perror("too many clients, nfds size is not enough.");
exit(EXIT_FAILURE);
}
}
}
handle_conn(nfds, buf);
}
close(listen_sock);
}
inthandle_conn(struct pollfd *nfds, char* buf){
int n = 0;
for (int i=1;i<OPEN_MAX;++i) {
if (nfds[i].fd<0) {
continue;
}
if (nfds[i].revents & POLLIN) {
bzero(buf, MAX_BUF);
n = read(nfds[i].fd, buf, MAX_BUF);
if (0 == n) {
close(nfds[i].fd);
nfds[i].fd = -1;
continue;
}
if (n>0){
printf("recv from client: %s\n", buf);
nfds[i].events = POLLIN;
close(nfds[i].fd); //接收数据后就主动关闭连接,用于RST测试
} else {
perror("read failure.");
exit(EXIT_FAILURE);
}
} elseif (nfds[i].revents & POLLOUT) {
printf("write data to client: %s\n", buf);
write(nfds[i].fd, buf, sizeof(buf));
bzero(buf, MAX_BUF);
nfds[i].events = POLLIN;
}
}
return0;
}
intset_linger(int sock, int l_onoff, int l_linger){
structlingerso_linger;
so_linger.l_onoff = l_onoff;
so_linger.l_linger = l_linger;
int r = setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger));
return r;
}
抓包结果如下:
先3次握手,后客户端向服务度发送了5个字节数据,服务端在接收完5字节数据向客户端ACK后,表示想中断连接,此时因设置了SO_LINGER选项值为0,close()时,直接向对方发送RST而不是正常的发送FIN,连接立即终止,并且不会有TIME_WAIT状态,TCP将丢弃残留在发送缓冲区中的数据,对方read()时将收到Connection reset by peer的错误。