poll---socket客户/服务器端编程

poll函数类似于select,但是程序接口有所不同。poll函数任何类型的文件描述符。

在用poll函数编写程序之前,我们先来看看poll函数的原型:

int poll(struct pollfd* fds,nfds_t nfds,int timeout);

我们来看看它的参数:

第一参数是指向一个结构数组第一个元素的指针。每个数组元素都是一个pollfd结构,用于指定测试某个给定描述符fd的条件。与select不同,poll不是为每个条件(可读性,可写性和异常条件)构造一个描述符集,而是构造一个pollfd结构的数组,每个数组元素指定一个描述符编号以及我们对该描述符感兴趣的条件。这个结构体如下:

struct pollfd{

int fd;

short events;

short revents;

}

数组中的元素数由nfds指定。要测试的条件由events成员指定,这样我们就告诉了内核我们关心的是每个描述符的哪些事件。函数在相应的revents成员中返回该描述符的状态,revents成员由内核设置,用于说明每个描述符发生了哪些事件。

第三个参数和select一样,有3种不同的情形,指的是我们愿意等待多长时间。

当timeout为-1时,说明要永远等待,一直等。当所指定的描述符中的一个已准备好,或捕捉到一个信号时返回。

当timeout为0时,我们不等待。测试所有描述符并立即返回。可以说这是一种轮询方法,可以找到多个描述符的状态而不阻塞poll函数。

当timeout大于0时,我们等待timeout毫秒。当指定的描述符之一以准备好,或timeout超时时立即返回。如果timeout到期时还没有一个描述符准备好,则返回值是0;

如果我们不再关心某个特定描述符,那么我们可以把与它对应的pollfd结构的fd成员设置成一个负值。poll函数将忽略这样的pollfd结构的events成员,返回时将它的revents成员的值置为0。

接下来我们来看看具体的代码,用poll函数实现一个简单的客户/服务端模型:

server端:

#include <stdio.h>
   #include <stdlib.h>
   #include <assert.h>
   #include <poll.h>
   #include <unistd.h>
   #include <netinet/in.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <arpa/inet.h>
  
  #define _BACKLOG_ 5
  #define _CLIENT_ 64
  
  static void usage(const char* arg)
  {
      printf("usage:%s [ip][port]",arg);
  }
  
  static int start(char *ip,int port)
  {
      assert(ip);
      int sock=socket(AF_INET,SOCK_STREAM,0);                                                                                                                         
      if(sock<0)
      {
          perror("socket");
          exit(1);
      }
      struct sockaddr_in local;
      local.sin_family=AF_INET;
      local.sin_port=htons(port);
      local.sin_addr.s_addr=inet_addr(ip);
  
      if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
      {
          perror("bind");
          exit(2);
      }
  
      if(listen(sock,_BACKLOG_)<0)
      {
          perror("listen");
          exit(3);
      }
  
      return sock;
  }
  
  int main(int argc,char *argv[])
  {
      if(argc!=3)
      {
          usage(argv[0]);                                                                                                                                             
          exit(1);
      }
      int i,maxi;//client数组的最大下标
      int port=atoi(argv[2]);
      char *ip=argv[1];
  
      int listenfd=start(ip,port);
      int done=0;
      int new_sock=-1;
      struct sockaddr_in client;
      socklen_t len=sizeof(client);
      struct pollfd clientfds[_CLIENT_];
  
      clientfds[0].fd=listenfd;
      clientfds[0].events=POLLIN;
      int _timeout=5000;
      for(i=1;i<_BACKLOG_;++i)
      {
          clientfds[i].fd=-1;      }
      maxi=0;
     int ret;
     while(1)
     {
         ret=poll(clientfds,maxi+1,_timeout);
         if(ret<0)
         {
             printf("poll error\n");
             exit(1);
 
         }
         else if(ret==0)
         {
             perror("time out");
             //exit(2);                                                                                                                                              
         }
         if(clientfds[0].revents&POLLIN)
         {
             new_sock=accept(listenfd,(struct sockaddr*)&client,&len);            
             printf("get a connect...%d\n",new_sock);
             for(i=1;i<_CLIENT_;++i)
             {
                 if(clientfds[i].fd<0)
                 {
                     clientfds[i].fd=new_sock;   //save descriptor
                     break;
                 }
             }
             if(i==_CLIENT_)
             {
 
                 close(new_sock);
             }
             clientfds[i].events=POLLIN;
             if(i>maxi)
             {
                 maxi=i;
             }
         }                                                                                                                                                           
 
         for(i=1;i<=maxi;++i)
         {
             if(clientfds[i].fd<0)
             {
                 continue;
             }
             if(clientfds[i].revents&POLLIN)
             {
                 char buf[1024];
                 ssize_t _s=read(clientfds[i].fd,buf,sizeof(buf)-1);
                 if(_s>0)
                 {
                     buf[_s]=‘\0‘;
                     printf("client: %s",buf);
                 }
                 else if(_s==0)
                 {
                     printf("client quit...\n");
                     close(clientfds[i].fd);
                     clientfds[i].fd=-1;
                 }
             }
         }
     }
     return 0;
 }

client端:

#include <stdio.h>
   #include <stdlib.h>
   #include <assert.h>
   #include <poll.h>
   #include <unistd.h>
   #include <netinet/in.h>
   #include <sys/types.h>
   #include <sys/socket.h>
   #include <arpa/inet.h>
  
  static void usage(const char* arg)
  {
      printf("usage:%s [ip][port]",arg);
  }
  
  int main(int argc,char *argv[])
  {
      if(argc!=3)
      {
          usage(argv[0]);
          exit(1);
      }
  
      int port=atoi(argv[2]);
      char *ip=argv[1];
  
      int sock=socket(AF_INET,SOCK_STREAM,0);
      if(sock<0)
      {
          perror("socket");
          exit(2);
      }
                                                                                                                                                                      
      struct sockaddr_in remote;
      remote.sin_family=AF_INET;
      remote.sin_port=htons(port);
      remote.sin_addr.s_addr=inet_addr(ip);
  
      int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote));
                                                                                                                                                                      
      char buf[1024];
      while(1)
      {
          printf("please enter: ");
          fflush(stdout);
          ssize_t _s=read(0,buf,sizeof(buf)-1);
          buf[_s]=‘\0‘;
          write(sock,buf,sizeof(buf)-1);
      }
      return 0;
  }

上面代码的运行结果如下:

从上面的额结果我们看到,客户端发送的数据被服务短板收到了,服务端在我们设定timeout超时后会给我打印出一条“time out :success”消息,至此整个程序编写完成。

时间: 2024-11-02 17:42:16

poll---socket客户/服务器端编程的相关文章

基于UDP的socket客户服务器编程

前面我们写了关于TCP的客户/服务器模式,现在我们写关于UDP的客户/服务器模式. 基于TCP编写的应用程序和基于TCP编写的应用程序之间存在一些本质的差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议,不同于TCP提供的面向连接的可靠字节流. 我们先来说一下简单的模型:在基于UDP的应用程序中,客户不与服务器建立连接,而只是使用sendto函数给服务器发送数据报,其中必须指定目的地(即服务器)的地址作为参数.当然,在服务器端不接受来自客户的连接,只是使用recvfrom函

【Socket编程】通过Socket实现TCP编程

通过Socket实现TCP编程 Socket通信 : 1.TCP协议是面向对象连接.可靠的.有序的,以字节流的方式发送数据. 2.基于TCP协议实现网络通信的类: 客户端----Socket类 服务器端----ServerSocket类 一.通信过程(Socket通信模型) Socket通信模型用下图所示: 1.在服务端建立一个ServerSocket,绑定相应的端口,并且在指定的端口进行侦听,等待客户端的连接. 2.当客户端创建连接Socket并且向服务端发送请求. 3.服务器收到请求,并且接

九、Socket之TCP编程

TCP简介 TCP是Transmission Control Protocol(传输控制协议)的简称,是TCP/IP体系中面向连接的运输层协议,在网络中提供全双工的和可靠的服务. TCP最主要的特点: (1)是面向连接的传输层协议: (2)每个TCP连接只能有两个端点,而且只能一对一通信,不能一点对多点直接通信. (3)通过TCP连接传送的数据,能保证数据无差错.不丢失.不重复地准确到达接收方,并且保证各数据到达的顺序与数据发出的顺序相同. (4)数据以字节流的方式传输. (5)传输的数据无消息

基于Socket实现网络编程

Socket是网络上两个程序间双向通讯的一端,它既可以发送请求,也可以接收请求,利用它可以方便的编写网络上数据的传递,在java中,有专门的类类处理用户的请求和响应.利用Socket 类的方法,就可以实现两台计算机之间的通信,那么怎么利用socket进行网络编程呢?我试试水~ 网络中的进程之间是如何进行通信的? 本地进程间通信(IPC)有很多种方法,简而言之可以归结为以下四类: 消息传递(管道,FIFO,消息队列); 同步(互斥量,条件变量,读写锁,文件和写记录锁,信号量): 内存共享(匿名的和

《Linux多线程服务器端编程》读书笔记第3章

<Linux多线程服务器端编程>第3章主要讲的是多线程服务器的适用场合与常用的编程模型. 1.进程和线程 一个进程是"内存中正在运行的程序“.每个进程都有自己独立的地址空间(address space).将"进程"比喻为"人",每个人都有自己的记忆(memory),人与人通过谈话(消息传递)来交流,谈话既可以是面谈(同一台服务器),也可以在电话里谈(不同的服务器,有网络通信).面谈和电话谈的区别在于,面谈可以立即知道对方是否死了(crash,S

服务器端编程心得(三)—— 一个服务器程序的架构介绍

本文将介绍我曾经做过的一个项目的服务器架构和服务器编程的一些重要细节. 一.程序运行环境 操作系统:centos 7.0 编译器:gcc/g++ 4.8.3     cmake 2.8.11 mysql数据库:5.5.47 项目代码管理工具:VS2013 二.程序结构 该程序总共有17个线程,其中分为9个数据库工作线程D和一个日志线程L,6个普通工作线程W,一个主线程M.(以下会用这些字母来代指这些线程) (一).数据库工作线程的用途 9个数据库工作线程在线程启动之初,与mysql建立连接,也就

[转] C#.Net Socket网络通讯编程总结

1.理解socket1).Socket接口是TCP/IP网络的应用程序接口(API).Socket接口定义了许多函数和例程,程序员可以用它们来开发TCP/IP网络应用程序.Socket可以看成是网络通信上的一个端点,也就是说,网络通信包括两台主机或两个进程,通过网络传递它们之间的数据.为了进行网络通信,程序在网络对话的每一端都需要一个Socket. 2).TCP/IP传输层使用协议端口将数据传送给一台主机的特定应用程序,从网络的观点看,协议端口是一个应用程序的进程地址.当传输层模块的网络软件模块

服务器端编程示例

int fd_set_nonblock(int fd) { int rv; rv = fcntl(fd, F_GETFL, 0); if(rv < 0){ printf("fcntl error\n"); return -1; } rv = fcntl(fd, F_SETFL, rv | O_NONBLOCK); if(rv < 0){ printf("fcntl error\n"); return -1; } return 0; } int init_

服务器端编程

我们的整个讨论都忽略了服务器端编程的问题.如果向服务器发出一个请求,会发生什么事情?大多数时候 的请求都是很简单的一个"把这个文件发给我".浏览器随后会按适当的形式解释这个文件:作为HTML 页. 一幅图.一个Java 程序片.一个脚本程序等等.向服务器发出的较复杂的请求通常涉及到对一个数据库进行 操作(事务处理).其中最常见的就是发出一个数据库检索命令,得到结果后,服务器会把它格式化成HTML 页,并作为结果传回来(当然,假如客户通过 Java 或者某种脚本语言具有了更高的智能,那么