网络编程-02TCP并发服务器

一、基于套接字的TCP通信

服务器流程:socket()-->bind()-->listen()-->accept()-->read()/write()-->close()
客户端流程:socket()-->connect()-->read()/write()-->close()

二、服务器模型

1.循环服务器

int sockfd=socket();
bind();
listen();
while(1)
{
    int connfd=accept();
    while(1)
    {
        read()/write();    
    }
    close(connfd);
}
close(sockfd);

2.并发服务器

(1)多进程并发服务器
pid_t pid;
int sockfd = socket();
bind();
listen();
signal();    //捕获子进程发出的信号,用于回收子进程资源
while(1)
{
    int connfd=accept();
    pid = fork();    //每连接一个客户就创建一个子进程
    if(pid==0)        //在子进程中完成信息交互
    {
        while(1)
        {
            read()/write();        
        }    
        close(connfd);
    }
    //wait(NULL);    
    //不能在这里回收资源,因为wait是阻塞函数,会阻碍客户端的下一次连接
}

注意事项:注意子进程结束后,子进程的资源回收问题,我们可以在父进程中通过调用signal函数捕获信号SIGCHLD,在对应的信号处理函数中完成资源回收

(2)多线程并发服务器
void *data_handler(void *arg);
pthread_t thread;
int main()
{
    int sockfd=socket();
    bind();
    listen();
    while(1)
    {
        int connfd=accpet();
        pthread_create(&thread,NULL,data_handler,&connfd);
        pthread_detach(thread);  //线程分离,资源回收                                      
    }
}
void *data_handler(void *arg)
{
    int connfd=*(int *)arg;
    while(1)
    {
        read(connfd)/write(connfd);            
    }
    close(connfd);
}

注意事项:使用多线程并发需要考虑公共资源保护的问题(同步、互斥)

检测进程运行信息

netstat -apn | grep “端口号”
netstat -apn | grep “6060”

三、TCP连接的三次握手过程

TCP头部结构

在这里插入图片描述
在这里插入图片描述

UDP头部结构

在这里插入图片描述
所以UDP发送消息不保证在这里插入图片描述

三次握手(连接时):

第一次:
    客户端向服务器发送SYN(x)待确认数据标志位,
    客户端进入SYN_SEND状态(准备发送)
第二次:
    服务器向客户端回传一条ACK(x+1)应答,同时带上SYN(y)待确认数据标志位,
    服务器进入SYN_RECV状态(准备接受)
第三次:
    客户端向服务器回传一条ACK(y+1)应答,建立连接成功,
    双方同时进入ESTABLISHED状态(已连接)

在这里插入图片描述

四、四次挥手过程

四次挥手(断开时)

FIN、ACK

第一次:
    主动方发送一个FIN报文请求断开,此时主动方进入FIN_WAIT1状态
第二次:
    被动方发送一个ACK应答,说明被动方已经收到,并进入CLOSE_WAIT状态,
    主动方,进入了半关闭状态
第三次:
    被动方发出FIN报文,标识自己想断开连接,进入LAST_FIN状态
第四次:
    主动方,发出ACK应答后,进入了TIME_WAIT状态,等待ACK报发完
          TIME_WAIT大概持续45s左右(具体由不同编译器而定),结束后两个都close
    (这也就是平时使用时,先断开服务器再断开客户端,再打开服务器会显示已经被使用等45s即可)
   
     若主动方是客户端(先结束客户端,在结束服务器),TIME_WAIT状态就无关紧要,影响不了服务器的连接

在这里插入图片描述
主动方为服务器:
服务器客户端都在运行时:
在这里插入图片描述
服务器(主动方)发出FIN断开,客户端暂时不断开,发出ACK应答:前两次挥手
在这里插入图片描述
客户端断开,发出FIN,服务器发出ACK应答,进入TIME_WAIT:后两次挥手
在这里插入图片描述
45s后进程退出
在这里插入图片描述
主动方为客户端:
都在运行(ESTABLISHED)
在这里插入图片描述
客户端断开:
在这里插入图片描述
服务器断开:
在这里插入图片描述

在TCP连接的关闭过程中,有四次挥手的步骤。
第一次挥手由服务器发起,它向客户端发送一个FIN(Finish)分组,表示服务器要关闭连接。
客户端接收到FIN后,进入CLOSE_WAIT状态。
接下来客户端发送一个ACK(Acknowledgement)分组,确认收到服务器的关闭请求。
然后客户端发送一个FIN分组,表示客户端也要关闭连接。
服务器接收到FIN后,进入LAST_ACK状态。
最后服务器发送一个ACK分组,确认收到客户端的关闭请求,然后进入TIME_WAIT状态。
客户端接收到服务器发送的ACK后,进入TIME_WAIT状态。

区别在于,服务器主动断开连接时,进入FIN_WAIT状态。
这是因为服务器通常同时处理多个连接,所以在关闭一个连接之后需要等待一段时间,
    以确保对方收到FIN分组并发送了ACK分组。
    如果服务器没有收到对方的确认,那么它会重新发送FIN分组并等待。
而客户端断开连接时,直接进入TIME_WAIT状态。
    这是为了防止在连接关闭后的一段时间内,可能仍然有处于网络中的延迟分组到达。

保持TIME_WAIT状态可以确保服务器收到客户端的ACK分组,从而避免造成混乱和数据丢失。

总结一下,服务器断开连接有FIN_WAIT状态,是为了确保对方收到FIN分组并发送了ACK分组。
而客户端直接进入TIME_WAIT状态,是为了确保服务器收到ACK分组并防止数据丢失。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值