Poll机制

来源:互联网 发布:2014年程序员考试真题 编辑:程序博客网 时间:2024/06/05 19:47

echo应答协议

echo会将输入的字符串送往标准输出。输出的字符串间以空白字符隔开,并在最后加上换行号。

echo server:功能是客户端向服务器发送消息,服务器接收输出并原样返回客户端。

Server

/*************************************************************************    > File Name: poll.cpp    > Author:     > Mail:     > Created Time: 2017年06月17日 星期六 14时28分03秒 ************************************************************************/#include<iostream>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<strings.h>#include<string.h>#include<errno.h>#include<sys/wait.h>#include<poll.h>#define IPADDRESS "127.0.0.1"#define PORT 6666#define MAXLINE 1024#define LISTENQ 5#define OPEN_MAX 1000#define INTTIM -1using namespace std;int bind_and_listen()//服务器端创建套接字,绑定,并监听,返回创建的套接字描述符,如果返回负值,表示有错误,具体见代码{    int serverfd;//服务器套接字,监听    struct sockaddr_in my_addr;    unsigned int sin_size;    if((serverfd=socket(AF_INET,SOCK_STREAM,0))==-1){        perror("scoket error!\n");        return -1;    }    printf("socket OK!\n");    my_addr.sin_family=AF_INET;    my_addr.sin_port=htons(PORT);//这边端口号没有转化为主机字节序,导致客户端连不上。(忘了加htons)    my_addr.sin_addr.s_addr=INADDR_ANY;//服务器地址配置    bzero(&(my_addr.sin_zero),0);//为啥把这个设置为0,需要查查???    if(bind(serverfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr))==-1){        perror("bind error\n");        return -2;    }    printf("bind OK!\n");    if(listen(serverfd,LISTENQ)==-1){        printf("listen error\n");        return -3;    }    printf("listen ok!\n");    return serverfd;}void do_poll(int listenfd)//IO多路复用poll{    int connfd,sockfd;    struct sockaddr_in clientaddr;    socklen_t clientaddrlen=sizeof(clientaddr);    struct pollfd clientfds[OPEN_MAX];//使用poll机制最大能够处理的事件个数,这里取名clientfds言外之意就是处理客户端个数    clientfds[0].fd=listenfd;    clientfds[0].events=POLLIN;//clientfds[0]的事件属性events设置为可读    //其他的fd都初始化为-1    for(int i=1;i<OPEN_MAX;i++)        clientfds[i].fd=-1;    int ready_events_num=0;    int events_num=1;//用于标记poll函数中第一个参数的元素个数    int max_index=0;    while(1)    {        ready_events_num=poll(clientfds,max_index+1,INTTIM);//timeout为INTTIM(-1)表示无限等待,就是进程挂起,直到有事件发生。返回发生事件的个数,=0表示没有,大于0就是有,小于0(-1)表示出错。        if(ready_events_num==-1){            perror("poll error\n");            exit(1);        }        if(clientfds[0].revents&POLLIN)//先测试监听描述符(服务器描述符),接受新的连接        {            if((connfd=accept(listenfd,(struct sockaddr*)&clientaddr,&clientaddrlen))==-1){                if(errno==EINTR)//请求的事件之前产生一个信号,调用可以重新发起                    continue;                else                {                    perror("accept error\n");                    exit(1);                }            }            fprintf(stdout,"accept a new client: %s:%d\n",inet_ntoa(clientaddr.sin_addr),clientaddr.sin_port);//IP以点分十进制输出,以及端口号            int i;            for(i=1;i<OPEN_MAX;i++)            {                if(clientfds[i].fd<0)                {                    clientfds[i].fd=connfd;//客户端的描述符加入到clientfds中                    break;                }            }            if(i==OPEN_MAX){                fprintf(stderr,"too many clients.\n");                exit(1);            }            clientfds[i].events=POLLIN;//设置新添加的clientfds[i]为可读            max_index=(i>max_index)?i:max_index;//发生事件,最大的下标            if(ready_events_num<=1)//说明只有服务器描述符clientfds[0]有变化(接收新的客户端),其他无变化                continue;        }        char buff[MAXLINE];//        memset(buff,0,MAXLINE);        for(int i=1;i<=max_index;i++)//处理多个客户端发来的包        {            if(clientfds[i].fd<0)                continue;            if(clientfds[i].revents&POLLIN)//客户端发来信息,服务器端有数据可读            {                int len=read(clientfds[i].fd,buff,MAXLINE);                if(len==0){//关闭连接,具体查查返回值的意义                    close(clientfds[i].fd);                    clientfds[i].fd=-1;                    continue;                }                write(STDOUT_FILENO,buff,len);//写入STDOUT_FILEENO,不知道啥意思???                write(clientfds[i].fd,buff,len);//把buf信息发回去            }        }    }}int main(int argc,char **argv){    int listenfd=bind_and_listen();    if(listenfd<0)        return 0;    do_poll(listenfd);    return 0;}

Client

/*************************************************************************    > File Name: client.cpp    > Author:     > Mail:     > Created Time: 2017年06月17日 星期六 15时49分43秒 ************************************************************************/#include<iostream>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>#include<strings.h>#include<string.h>#include<errno.h>#include<sys/wait.h>#include<poll.h>#define IPADDRESS "127.0.0.1"#define PORT 6666#define MAXLINE 1024#define max(a,b) (a>b)?a:busing namespace std;static void handle_connection(int sockfd);int main(int argc,char**argv){    int connfd=0;    int clen=0;    struct sockaddr_in client;    if(argc<2){        printf("Usage: client [server IP address]\n");        return -1;    }    client.sin_family=AF_INET;    client.sin_port=htons(PORT);//转化为主机字节序    client.sin_addr.s_addr=inet_addr(argv[1]);//这个命名有问题,其实是服务器的地址    if((connfd=socket(AF_INET,SOCK_STREAM,0))==-1){        perror("socket error\n");        return -1;    }    int conres;    if((conres=connect(connfd,(struct sockaddr*)&client,sizeof(client)))<0){        cout<<conres<<endl;                perror("connect error\n");        return -1;    }    handle_connection(connfd);    return 0;}static void handle_connection(int sockfd){    char sendline[MAXLINE],recvline[MAXLINE];    struct pollfd pfds[2];    pfds[0].fd=sockfd;    pfds[0].events=POLLIN;    pfds[1].fd=STDIN_FILENO;//把标准输入添加到描述符pfds[1]中    pfds[1].events=POLLIN;    while(1)    {        poll(pfds,2,-1);        if(pfds[0].revents&POLLIN)        {            int n=read(sockfd,recvline,MAXLINE);//读取服务器向客户端sockfd发来的信息            if(n==0){                fprintf(stderr,"client: server is closed.\n");                close(sockfd);            }            write(STDOUT_FILENO,recvline,n);//向标准输出写收到的信息        }        if(pfds[1].revents&POLLIN)//测试标准输入是否准备好        {            int n=read(STDIN_FILENO,sendline,MAXLINE);            if(n==0){                shutdown(sockfd,SHUT_WR);//这个不太理解是啥意思                continue;            }            write(sockfd,sendline,n);        }    }}

makefile

all:server clientserver: server.o    g++ -g -o server server.oclient: client.o    g++ -g -o client client.oserver.o: server.cpp    g++ -g -c server.cppclient.o:client.cpp    g++ -g -c client.cppclean :all    rm all

gdb传参数

    #include<stdio.h>      int main(int argc, char *argv[])      {          int i;          for(i = 0; i < argc; ++i)          {              printf("%s/n", argv[i]);          }      }  

开始调试:

$gdb a.out

之后,在输入start之前:

使用命令设置main的参数,例如:

set args abc 123

这样 argv[1]就是”abc”

argv[2]是”123”