poll机制 socket进程间通讯
poll,Linux中的字符设备驱动中有一个函数,Linux 2.5.44版本后被epoll取代。
poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明:
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
此函数在系统调用select内部被使用,作用是把当前的文件指针挂到设备内部定义的等待
队列中。这里的参数table可以不考虑,是在select函数实现过程中的一个内部变量。
函数具体实现时:
wait_queue_head_t t = ((struct mydev *)filp->private_data)->wait_queue;
poll_wait(filp, t, table);
return mask;
这里mask可以是:POLLIN | POLLRDNORM POLLOUT | POLLWRNORM等等。
poll和select实现功能差不多,但poll效率高,以后要多用poll
poll()接受一个指向结构'struct pollfd'列表的指针,其中包括了你想测试的文件描述符和事件。事件由一个在结构中事件域的比特掩码确定。当前的结构在调用后将被填写并在事件发生后返回。在SVR4(可能更早的一些版本)中的 "poll.h"文件中包含了用于确定事件的一些宏定义。事件的等待时间精确到毫秒 (但令人困惑的是等待时间的类型却是int),当等待时间为0时,poll()函数立即返回,-1则使poll()一直挂起直到一个指定事件发生。下面是pollfd的结构。
struct pollfd {
int fd; /*文件描述符*/
short events; /* 等待的需要测试事件 */
short revents; /* 实际发生了的事件,也就是返回结果 */
};
与select()十分相似,当返回正值时,代表满足响应事件的文件描述符的个数,如果返回0则代表在规定时间内没有事件发生。如发现返回为负则应该立即查看 errno,因为这代表有错误发生。
|
常量
|
说明
|
|
POLLIN
|
普通或优先级带数据可读
|
|
POLLRDNORM
|
普通数据可读
|
|
POLLRDBAND
|
优先级带数据可读
|
|
POLLPRI
|
高优先级数据可读
|
|
POLLOUT
|
普通数据可写
|
|
POLLWRNORM
|
普通数据可写
|
|
POLLWRBAND
|
优先级带数据可写
|
|
POLLERR
|
发生错误
|
|
POLLHUP
|
发生挂起
|
|
POLLNVAL
|
描述字不是一个打开的文件
|
//client.c // run$ ./client.o 127.0.0.1 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; struct sockaddr_in servaddr; if (argc != 2) { printf("usage: ./client <ipaddress>\n"); exit(0); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) { printf("inet_pton error for %s\n",argv[1]); exit(0); } if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); if (send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } if ((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) { perror("recv error"); exit(1); } buf[rec_len] = '\0'; printf("Received : %s ",buf); close(sockfd); exit(0); }
//server.c #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<poll.h> #define DEFAULT_PORT 8000 #define MAXLINE 4096 #define IN_FILES 1 //我们这里poll机制只监听一个文件描述符 void socket_accept(int socket_fd) { int connect_fd; char buff[MAXLINE]; //阻塞直到有客户端连接,不然浪费CPU资源,但是显然这里通过poll机制是有可读的信息才会进入本函数,因此应该是不会阻塞的。 if ((connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1) { printf("accept socket error: %s(errno: %d)",strerror(errno),errno); } int n = recv(connect_fd, buff, MAXLINE, 0); buff[n] = '\0'; printf("recv msg from client: %s\n", buff); if (send(connect_fd, "Hello,you are connected!\n", 26, 0) == -1) { perror("send error"); } close(connect_fd); } int main(int argc, char** argv) { int socket_fd, connect_fd; struct sockaddr_in servaddr; struct pollfd fds[IN_FILES]; //初始化Socket if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } //初始化 memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。 servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT //将本地地址绑定到所创建的套接字上 if (bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) { printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } //开始监听是否有客户端连接 if (listen(socket_fd, 10) == -1) { printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } fds[0].fd = socket_fd; fds[0].events = POLLIN; int result; while(1){ printf("begin to poll()\n"); result = poll(fds, IN_FILES, 3000); //It may block with timeout if (result == 0) { printf("Poll timeout\n"); } else if (result > 0) { printf("Poll successfully\n"); } else { printf("Poll error\n"); } if (fds[0].revents == POLLIN){ printf("===receive a connetction====\n"); socket_accept(socket_fd); } printf("do something else\n"); sleep(1); printf("do something else end\n"); } close(socket_fd); }
Server:
~/c/socket$ ./server.o
begin to poll()
Poll timeout
do something else
do something else end
begin to poll()
Poll successfully
===receive a connetction====
recv msg from client: sdfsfsdsdrf455
do something else
do something else end
begin to poll()
Poll timeout
do something else
Client:
:~/c/socket$ ./client.o 127.0.0.1
send msg to server:
sdfsfsdsdrf455
Received : Hello,you are connected!
daichenghui@daichenghui-OptiPlex-3020:~/c/socket$

浙公网安备 33010602011771号