TCP调用listen处于监听状态,listen的第二个参数含义
Posted 两片空白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP调用listen处于监听状态,listen的第二个参数含义相关的知识,希望对你有一定的参考价值。
现象
用TCP协议写两个程序,服务器端listen的第二个参数设为1,不调用accept。
说明:只要服务器端处于listen状态,就可以建立连接,与accept无关。
#pragma once
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
class Server{
private:
int _port;
int _lsock;
public:
Server(int port = 8080)
:_port(port)
,_lsock(-1)
{}
void initServer(){
//自定义SIGCHLG信号的捕捉方式为忽略,子进程自动回收
signal(SIGCHLD,SIG_IGN);
_lsock = socket(AF_INET, SOCK_STREAM, 0);
if(_lsock < 0){
std::cerr <<"socket error"<<std::endl;
exit(1);
}
int opt = 1;
setsockopt(_lsock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(_lsock,(struct sockaddr *)&local, sizeof(local)) < 0){
std::cerr<<"bind error"<<std::endl;
exit(2);
}
if(listen(_lsock, 1) < 0){
std::cerr<<"listen error"<<std::endl;
exit(3);
}
}
void Start(){
//不进行accept
while(1){
sleep(1);
}
}
~Server(){
close(_lsock);
}
};
#include "server.hpp"
int main(int argc, char *argv[]){
if(argc != 2){
std::cout<<"please enter argv[0] server_port"<<std::endl;
exit(1);
}
Server *s = new Server(atoi(argv[1]));
s->initServer();
s->Start();
return 0;
}
现象:
结论
因为在TCP内核协议栈为TCP管理使用了两个队列:
- 半连接队列:用来保存还没有连接完成的请求。(连接请求处于SYN_RECV或者SYN_SENT状态)
- 全连接队列:用来保存连接完成的请求,处于ESTABLISHED状态的请求。
accept就是从全连接队列中,拿已经连接好的请求。内核再从半连接队列中,将半连接请求连接完成,加到全连接队列中。
为什么会有半连接状态?
因为全连接队列满了,无法继续让当前队列进入ESTABLISHED状态。
全连接队列长度等于listen第二个参数值加1。
内核表现
内核需要管理请求,先描述再组织,描述的结构体是request_sock。通过单向链表管理。
为什么全连接队列长度等于listen第二个参数值加1?
以上是关于TCP调用listen处于监听状态,listen的第二个参数含义的主要内容,如果未能解决你的问题,请参考以下文章