(四) 用poll实现TCP服务端

原创 2017年01月03日 10:14:48

1.首先,大概说一下poll函数的工作大概:(包含在#include<poll.h>当中)

        poll 是通过监听一个结构体变量来对 文件描述符进行监听的(当然,socket也算是一个文件描述符)

        这个结构体的大概结构是:

       (!!如果不想了解poll工作原理的。可以直接拉下去看代码)

struct pollfd   //这个结构体一般会被定义为结构体数组
{
   int fd;        //要监听的文件描述符
   short events;  //期待fd发生的事件   ,其中 events把他设置成 POLLIN就够用了,表示检测该fd有没有可读数据
   short revents; //fd实际发生的事件
};		

而poll()是通过监听上述结构体数组 来监听一堆文件描述符的
2.再来了解poll()函数详细信息:
    (一)首先是他的输入参数:
            int poll(struct pollfd *name,int num,int timeout);
              一共有三个,分别是监听的结构体数组的数组名,实际监听着多少个结构体数组成员,阻塞时间控制参数。
             其中timeout参数 ==0,是非阻塞,== -1 是阻塞,>0是阻塞 xx毫秒
   (二)然后是他的返回值
          poll()函数的返回值   ,表示同时有响应的文件描述符个数。
接下来看看 poll()的大致使用例子:

3.给出代码:(在这之前先看看代码的大致实现逻辑)
首先把 监听套接字sock 和 标准输入 先放到 监听的结构体数组中
while(1)循环是必须的,在循环中,用poll()进行监听,然后判断是sock是否响应,是的话,就调用accept来获取连接进来的客户端的信息,并把接收到的socket放到结构体数组中。否则就继续往下(判断是否标准输入响应,是就读信息),再往下,判断是哪些客户端socket发生可读响应,有的话,就读。

//服务端
#include"myhead.h"
#define CLI_NUM 10
char rbuf[50];
char wbuf[50];
char ipbuf[50];
int recv_num;

struct pollfd pollfd[CLI_NUM];

void write_all(char *wbuf,int max)
{
	int i = 2;
	for(i;i<(max+2);i++)
	{
		write(pollfd[i].fd,wbuf,50);
	}
}

int main()
{

	int sockfd;
	int size,port;
	int new_sock;
	int on = 1;
	int i;
	
	int max = 0;
	int ret;
	struct sockaddr_in saddr;
	struct sockaddr_in caddr;
	size = sizeof(struct sockaddr_in);

	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(8888);
	saddr.sin_addr.s_addr = htonl(INADDR_ANY);

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

	bind(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));
	listen(sockfd,10);

	//init pollfd
	for(i=0;i<10;i++)    //把pollfd置 -1,当然不一定是-1,只是文件描述符不可能为负,所以就置成一个负数
	{
		pollfd[i].fd = -1;
	}

	

	pollfd[0].fd = sockfd;
	pollfd[0].events = POLLIN;

	pollfd[1].fd = STDIN_FILENO;
	pollfd[1].events = POLLIN;
	int len = sizeof(struct sockaddr);
	while(1)
	{
		puts("waiting poll");
		ret = poll(pollfd,max+2,-1);            //ret表示发生响应的文件描述符个数,接下来就要对这些响应的文件描述符都处理一次
		if(ret ==0)
		{
			perror("timeout");
			exit(-1);
		}

		if((pollfd[0].revents& POLLIN) == POLLIN)
		{
			puts("waiting accept");
			new_sock = accept(sockfd,(struct sockaddr*)&caddr,&len);
			
			write(new_sock,"get",4);
			if(new_sock>0)
			{
				//fcntl(new_sock,F_SETFL,fcntl(new_sock,F_GETFL)|O_NONBLOCK);
				printf("newfd =%d\n",new_sock);
				i = 2;
				for(i;i<CLI_NUM;i++)
				{
					if(pollfd[i].fd != -1)
						continue;
					else if(pollfd[i].fd == -1)
					{
						pollfd[i].fd = new_sock;
						pollfd[i].events = POLLIN;
						max +=1;
						printf("max=%d\n",max);
						ret-=1;                    //每处理一个就 -1
						if(ret <= 0 )              //要是响应的文件描述符都处理完了,就退出循环。
						{
							break;
						}
					
					}
				}
			}
		}

		if((pollfd[1].revents & POLLIN) == POLLIN)  //是否从键盘有信息读入
		{
			bzero(wbuf,50);
			scanf("%s",wbuf);
			write_all(wbuf,max);   
			ret-=1;                      //每处理一个就 -1
			if(ret<=0)
				continue;
		}

		for(i=2;i<CLI_NUM && pollfd[i].fd!=-1;i++)  //接收来自其他客户端的信息
		{
			
			if((pollfd[i].revents & POLLIN)==POLLIN)
			{
				
				puts("enter read");
				bzero(rbuf,50);
				recv_num = recv(pollfd[i].fd,rbuf,50,0);
				if(recv_num == 0)                          //当recv_num 为0,表示客户端已经退出了
				{
					printf("client close\n");
					close(pollfd[i].fd);
					pollfd[i].fd = -1;                 //既然客户端退出了,那原本该客户端占着的位置就重新置 -1
					continue;
				}
				printf("%s,from:%d\n",rbuf,pollfd[i].fd);
				write_all(rbuf,max);
				ret -=1;               
				if(ret<=0)
					break;
			}
		}
	
	}
}

接下来是客户端:
//客户端相对而言就比较简单
#include"myhead.h"
char rbuf[50];
char wbuf[50];
char ipbuf[50];

int main()
{
	int sockfd;
	int ret,port;
	struct pollfd pollfd[2];
	struct sockaddr_in saddr;
	int size = sizeof(struct sockaddr_in);
	bzero(&saddr,size);

	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(8888);
	saddr.sin_addr.s_addr = inet_addr("192.168.152.128");

	sockfd = socket(AF_INET,SOCK_STREAM,0);
	ret=connect(sockfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr));
	if(ret == 0)
	{
		inet_ntop(AF_INET,(void*)&saddr.sin_addr.s_addr,ipbuf,50);
		port = ntohs(saddr.sin_port);
		printf("%s,%d\n",ipbuf,port);
	}
	pollfd[0].fd = STDIN_FILENO;
	pollfd[0].events = POLLIN;

	pollfd[1].fd = sockfd;
	pollfd[1].events = POLLIN;
	while(1)
	{
		poll(pollfd,2,-1);
		if((pollfd[0].revents & POLLIN)==POLLIN)
		{
			puts("message from keyboard");
			bzero(wbuf,50);
			scanf("%s",wbuf);
			write(sockfd,wbuf,50);
		}
	
		if((pollfd[1].revents & POLLIN)==POLLIN)
		{
			bzero(rbuf,50);
			read(sockfd,rbuf,50);
			printf("%s\n",rbuf);
		}
	}
	return 0;
}














版权声明:本文为博主原创文章,未经博主允许不得转载。

实现TCP并发服务器之四(poll函数)

poll函数类似于select函数,但是它的程序员接口不同,尽管它也可用于任何类型 文件描述符。与select不同,poll不为每个状态(可读,可写,异常状态)构造一个描述符集,而是构造一个pollf...
  • ciaos
  • ciaos
  • 2012年07月04日 08:09
  • 1668

使用poll实现的io多路复用服务端和客户端

使用poll实现的io多路复用服务端和客户端。 客户端通过子进程创建多个客户端连接。 客户端每隔1秒向服务端发送一个时间戳, 服务端接收到时间戳以后,保存在本地的文件中, 一个客户端对应一个存储文件,...
  • robertkun
  • robertkun
  • 2016年08月21日 20:47
  • 838

Linux网络编程——tcp并发服务器(poll实现)

想详细彻底地了解poll或看懂下面的代码请参考《Linux网络编程——I/O复用之poll函数》 代码: #include #include #include #include #incl...
  • lianghe_work
  • lianghe_work
  • 2015年06月17日 17:13
  • 3069

利用TCP和多线程实现服务端和多个客户端建立实时聊天小案例

每当有一个客户端和服务端建立连接之后,服务端就会产生一个线程从而来产生一个Socket来和客户端连接 而客户端会产生两个线程,一个线程是用来获取标准键盘输入流InputStream,就是通过Syst...
  • lx__angel
  • lx__angel
  • 2018年01月03日 11:04
  • 40

基于linux poll模型的tcp服务器------一个服务器如何与多个客户端进行通信?

在之前的博文中, 我们一起玩了Windows下的select函数, 实现了一个服务器与多个客户端进行通信。 如果一直到linux, 那几乎是大同小异的。 现在, 我们不说select, 而来接续说说l...
  • stpeace
  • stpeace
  • 2017年06月24日 16:06
  • 2859

Modbus Poll 设置Modbus TCP通信超时时间

使用Modbus Poll可以轻松的用PC模拟Modbus主机,可以建立 Modbus RTU Modbus ASCII Modbus-TCP通信。 当使用Modbus TCP通信时,可以根据结点的多...
  • tcjy1000
  • tcjy1000
  • 2015年08月03日 12:41
  • 2859

C语言实现服务端和客户端进行TCP通信实例

 本文给出一个很实用的C语言实现的服务端和客户端进行TCP通信的小例子。具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考。 (1)客户端程序...
  • wpullo
  • wpullo
  • 2016年08月01日 11:47
  • 2256

基于TCP协议的Socket通信 实现用户登录 以及服务端的相应

服务端 package com.example; import java.io.BufferedReader; import java.io.IOException; import java....
  • csdndouniwan
  • csdndouniwan
  • 2016年10月28日 13:08
  • 1361

modbus poll的使用

Modbus测试工具 :Modbus Poll,Modbus Slave 1,简介 网站地址:http://www.modbustools.com/ 该网站提供了几个软件工具,可...
  • likai_lian
  • likai_lian
  • 2016年04月14日 09:48
  • 4277

linux C++ poll实现的聊天室程序 客户端----服务端

//该聊天室程序能让所有用户同时在线群聊,他分为客户端和服务端两个部分,其中客户端有两个功能,一是从标准输入终端读入用户数据,并将用户数据发送服务器,二是往标准输出端打印服务器发送给他的数据,服务器的...
  • u011676589
  • u011676589
  • 2013年08月16日 09:10
  • 1968
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:(四) 用poll实现TCP服务端
举报原因:
原因补充:

(最多只允许输入30个字)