IO多路复用(select)多线程实现点对点聊天

在网络编程中,IO操作不止本地的read或write,还会有网络套接字上的read和write。这样的话就容易出现这个问题:

当你用fgets函数在等待本地的标准输入,这时IO输入操作会阻塞在这里等待输入。如果此时网络套接字上传来了数据(比如说关闭连接命令),由于你的IO被阻塞在fgets处,无法及时知道网络套接字上传来的关闭命令。当你从fgets处获得数据后,再处理网络套接字发来的关闭命令的话,就响应不及时。

当然,IO会在读的时候阻塞,比如当缓冲区没有任何数据的时候,read会阻塞;写也会阻塞,比如缓冲区填满了数据,这时再用write写的话就会阻塞;连接tcp也会阻塞,当等待accept的队列已满时,就会出现连接阻塞。所以,IO阻塞的情况是经常发生的。

因此,为了解决IO被一个操作阻塞而对其他操作响应不及时的问题,就提出了IO多路复用。

IO多路复用最简单的就是利用select函数啦。

函数原型:

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int nfds, fd_set readfds, fd_set writefds, fd_set exceptfds, struct timeval timeout);

其中nfds是要监视的最大的文件描述符再加1,比如要监视标准输入(文件描述符为1),本地文件读(假设文件描述符为2),网络套接字读(假设文件描述符为3),则此时nfds = 3 + 1;

readfds,writefds, exceptfds是三个监视文件描述符集合。readfds是监视集合中的文件描述符是否可读,同理writefds 和 exceptfds分别监视集合中的文件描述符是否可写和是否异常。

timeout是定时器,如果在定时器规定的时间内select还没有发现已经准备好的(可读或可写或异常)文件描述符的话,就不再监视,直接返回。

具体select怎么用,请自己在linxu系统上man一下:man select

下面来说一下我用select写的点对点聊天小程序:

1.讲解:

该程序分为两部分,一部分是客户端程序,另一部分是服务器程序。之所以将这两部分合并成一个程序,是为了解决定向连接的问题——只能一端为服务器,另一端为客户端。将两部分合并后,先发起连接的一方就为客户端,被连接的一方为服务器。

2.源代码:

由于我的博客看代码没有行号等,不方便大家看。所以我把它发布到了oschina上了,点击下面的链接看代码:

http://www.oschina.net/code/snippet_1023919_20146

多了不解释,大家如果对多线程编程,select io多路复用,基本的read write函数以及tcp客户端和服务器程序流程比较熟悉的话,这个程序就很简单啦。该程序为本人原创,open-source,哈哈。

3.文件下载地址:

头文件:myhead.h

实现文件:ppp_chat.c