Open NeoZephyr opened 2 years ago
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MAXLINE 4096
int main(int argc, char** argv)
{
int sorkfd, n;
char recvline[4096], sendline(4096];
struct sockaddr_in servaddr:
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
for (n = 0; n < 100; n++) {
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d) \n"
strerror(errno), errno);
return 0:
}
// 客户端不停的向服务端发起新连接,成功之后继续发,没成功会阻塞在这里
if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d) \n", strerror(errno), errno);
return 0;
}
printf("connected to server: %d\n", n);
close(sockfd);
}
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<unistd.h>
#define MAXLINE 4096
int main(int argc, char* argv[])
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);
if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 1;
}
if (listen(listenfd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno):
return 2;
}
if ((connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
{
printf("accept socket error: %s(errno: %d)", strerror(errno), errno);
return 3;
}
printf("accepet a socket \n");
// 服务端仅 accept 一次,之后就不再 accept,此时全连接队列会被堆满
sleep(1000);
close(connfd);
close(listenfd);
return 0;
}
在 Linux中,一般情况下都是内核代理三次握手的,也就是说,当 client端调用 connect() 之后内核负责发送SYN,接收SYN-ACK,发送ACK。然后 connect() 系统调用才会返回,客户端侧握手成功
服务端的 Linux 内核会在收到SYN之后负责回复SYN-ACK再等待ACK之后才会让 accept() 返回,从而完成服务端侧握手。于是Linux内核就需要引入半连接队列(用于存放收到SYN,但还没收到ACK的连接)和全连接队列(用于存放已经完成3次握手,但是应用层代码还没有完成 accept() 的连接)两个概念,用于存放在握手中的连接
3.10 内核在全连接队列满的情况下,会先回复SYN-ACK,然后移进全连接队列时才发现满了于是丢弃连接,这样从客户端看来TCP连接成功了
在 4.9 内核中,对于全连接队列满的处理,就不一样,connect() 系统调用不会成功,一直阻塞,也就是说能够避免幽灵连接的产生
net.ipv4.tcp_tw_reuse net.ipv4.ip_local_port_range
connect 与 bind 端口选择区别