网络I/O学习(一)

一、什么是网络IO?

就是客户端和服务端之间的进行通信的通道(fd)。

二、网络IO通信步骤

1、建立套接字

int socketfd = socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //绑定0.0.0.0,Linux上有三张网卡,eth0:桥接,eth1:NAT,lo:回环,
                                                  // 0.0.0.0代表任意一个收到数据都行,也可以绑定固定网卡上的ip地址
servaddr.sin_port = htons(2000);              // 0~1023:系统使用,1024以后用户可以使用
if (-1 == bind(socketfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)))
{
    cout << "bind failed:" << strerror(errno) << endl;
}

2、实现监听

listen(socketfd, 10); //监听

struct sockaddr_in clientaddr; //创建一个客户端用于接受数据
socklen_t len = sizeof(clientaddr);
cout<<"current socketfd:"<<socketfd<<endl;
int clientfd = accept(socketfd, (struct sockaddr*)&clientaddr, &len);
cout<<"clientfd is:"<<clientfd<<endl;
netstat -anop | grep 2000		#新建一个窗口,输入该命令查看绑定的2000端口状态,  22查ssh,3306查mysql,6309查redis

在这里插入图片描述

如果再开一个窗口执行监听,那么会报错
在这里插入图片描述

3、接受数据 fd与tcp连接,io通道建立成功

会一直阻塞等待数据的到来

char buffer[1024] = {0};
int count = recv(clientfd, buffer, 1024, 0);
cout<<"buffer:"<<buffer<<endl;

4、返回信息

count = send(clientfd, buffer,count, 0);

5、由于代码中只存在两个fd,socketfd和clientfd

当存在一个客户端连接服务端时,可以正常收发消息;但当出现多个客户端连接服务端时,只有一个客户端能发信息,其余
客户端不能发送信息
在这里插入图片描述

在这里插入图片描述

客户端发送消息结果:
在这里插入图片描述

在这里插入图片描述

小结:

虽然3个客户端都连接服务端成功,但最终通信成功的只有一个,acept就调用成功一次就结束了,自然就接收不到其余两个客户端的数据

优化代码:

在这里插入图片描述

while (true)
    {
        cout<<"current socketfd:"<<socketfd<<endl;
        int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);
        cout<<"clientfd is:"<<clientfd<<endl;

        char buffer[1024] = {0};
        int count = recv(clientfd, buffer, 1024, 0);
        cout << "buffer:" << buffer << endl;

        //返回信息
        count = send(clientfd, buffer, count, 0);
    }

小结:

虽然都通信成功,但只能发送一次消息,无法发送第二次消息,在acept这进行了阻塞,而且必须根据连接顺序来处理信息,
比如连接顺序是1号,2号,3号客户端,3号连发3次消息,2号连发2次消息,此时服务端仍然没反应,在等待1号发消息,
1号发消息,然后服务端依次处理,将2号的2次消息,3号的3次消息全部发出,然后阻塞,需要有新的连接,然后才能处理消息。

存在两个问题:

1、无法实时响应。
2、一次性连接处理信息问题

三、多个IO如何接收数据

1、解决实时性问题和一次性连接处理问题

当多个客户端连接服务器时,accept会进行阻塞,等待第一个用户数据接收完之后,才处理第二个用户的请求…

解决方案:

采用多线程来解决。

void *ClientPthread(void *arg)
{
    int clientfd = *(int *)arg;
    while(true){
        cout<<"clientfd is:"<<clientfd<<endl;
        char buffer[1024] = {0};
        int count = recv(clientfd, buffer, 1024, 0);
        cout << "buffer:" << buffer << endl;

        //返回信息
        count = send(clientfd, buffer, count, 0);
    }
}
 while (true)
    {
        cout<<"current socketfd:"<<socketfd<<endl;
        int clientfd = accept(socketfd, (struct sockaddr *)&clientaddr, &len);

        pthread_t p_id;
        pthread_create(&p_id, NULL, ClientPthread, &clientfd);
    }

在这里插入图片描述

2、讨论fd的值

无论什么时候连接,或者多个客户端连接,发现socketfd的值永远是3,而接收客户端返回的fd却是在3的基础上+1
那么fd,0,1,2去哪了

ls /dev/fd

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

原来这三个值分别是代表标准输入,输出以及错误
那允许多少客户端连接呢,fd是个整数,肯定也存在一定的范围

ulimit -a

在这里插入图片描述

当前最多只支持到这么多

3、fd支持有限,那客户端断开连接后,原来的fd还能用吗?

答案是肯定的,系统有自己的回收策略

int count = recv(clientfd, buffer, 1024, 0);
   if(count == 0){                  //断开
       close(clientfd);            //必须要有close,不然系统不会回收fd资源
       break;
   }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值