TCP小型服务器(poll)

Posted xy913741894

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP小型服务器(poll)相关的知识,希望对你有一定的参考价值。

我们之前写过多线程,多进程,select机制的TCP服务器,作为IO复用的另一种机制poll,我们也有必要去学习一下,下面就是基于poll机制的服务器。

makefile

.PHONY:all
all:client server
client:client.c
    gcc -o $@ $^
server:server.c
    gcc -o $@ $^

server

/*************************************************************************
    > File Name: server.c
    > Author: xuyang
    > Mail: xy913741894@gmail.com 
    > Created Time: 2017-06-30 14:40:27
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/wait.h>
#include<assert.h>
#include <poll.h>


#define SIZE 1024


void usage(const char* arg)

    printf("correct usage : %s [ip] [port]\\n", arg);


int start_up(const char* ip, int port)

    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == -1)
    
        fprintf(stderr, "socket failure\\n");
        exit(-1);
    

    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_port = htons(port);
    inet_aton(ip, &local.sin_addr);

    int opt = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
    
        fprintf(stderr, "setsockopt failure\\n");
        exit(-1);
    

    int flag = bind(sock, (struct sockaddr*)&local, sizeof(local));
    if (flag == -1)
    
        fprintf(stderr, "bind failure\\n");
        exit(-1);
    
    flag = listen(sock, 6);
    if (flag == -1)
    
        fprintf(stderr, "listen failure\\n");
        exit(-1);
    
    return sock;



int main(int argc, char* argv[])

    if (argc != 3)
    
        usage(argv[0]);
        exit(-1);
    

    int sock_fd = start_up(argv[1], atoi(argv[2]));
    assert(sock_fd > 0);

    struct pollfd all_events[SIZE];

    int index = -1;
    for (; index < SIZE; ++index)
    
        all_events[index].fd = -1;
    
    struct pollfd evt;
    evt.fd = sock_fd;
    evt.events = POLLIN | POLLOUT;
    all_events[0] = evt;

    while (1)
    
        int flag = poll(all_events, SIZE, -1);
        switch(flag)
        
        case -1:
            printf("poll failure...\\n");
            break;
        case 0:
            printf("timeout...\\n");
            break;
        default:
            
                int i = 0;
                for (; i < SIZE; ++i)
                
                    int fd = all_events[i].fd;
                    if (i == 0 && (fd & POLLIN))
                    
                        struct sockaddr_in client;
                        socklen_t client_size = sizeof(client);
                        int new_fd = accept(fd, (struct sockaddr*)&client, &client_size);
                        if (new_fd < 0)
                        
                            fprintf(stderr, "accept failure\\n");
                            continue;
                        

                        printf("get a new client\\n");
                        //把client的描述符加入数组检测
                        int j = 0;
                        for (; j < SIZE; ++j)
                        
                            if (all_events[j].fd == -1)
                                break;
                        
                        if (j == SIZE)
                        
                            printf("server full\\n");
                            close(new_fd);
                         
                        else
                        
                            all_events[j].fd = new_fd;
                            all_events[j].events = POLLIN | POLLOUT;
                        
                    
                    else if (i != 0 && fd != -1)
                    
                        char buf[SIZE];
                        memset(buf, 0, SIZE);

                        while (1)
                        
                            ssize_t s = read(fd, buf, sizeof(buf) - 1);
                            if (s > 0)
                            
                                buf[s] = 0;
                                printf("client # %s\\n", buf);
                                write(fd, buf, strlen(buf));
                            
                            else if (s == 0)
                            
                                printf("client quits\\n");
                                break;
                            
                            else 
                            
                                printf("read error\\n");
                                break;
                            
                        
                        close(fd);
                    

                // end of for
            
            break;
        

    

    return 0;

client

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static void usage(const char* s)

    printf("correct usage : %s [remote_ip] [remote_port]\\n", s);


int get_socket(const char* ip, const char* port)

    int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_fd < 0)
    
        fprintf(stderr, "socket failure\\n");
        exit(1);
    

    struct sockaddr_in remote;
    remote.sin_family = AF_INET;
    remote.sin_port = htons(atoi(port));
    inet_aton(ip, &remote.sin_addr);

    // int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    int flag = connect(sock_fd, (struct sockaddr*)&remote, sizeof(remote));
    if (flag < 0)
    
        fprintf(stderr, "connect failure\\n");
        exit(2);
    
    return sock_fd;


int main(int argc, char* argv[])

    if (argc != 3)
    
        usage(argv[0]);
        exit(0);
    

    int sock_fd = get_socket(argv[1], argv[2]); 

    char buf[1024];
    while (1)
    
        memset(buf, '\\0', sizeof(buf));
        printf("please enter # ");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf)-1);
        if (s > 0)
        
            buf[s-1] = '\\0';
            write(sock_fd, buf, strlen(buf)); 
            s = read(sock_fd, buf, sizeof(buf)-1);
            if (s > 0)
            
                printf("server echo # %s\\n", buf);
            
        
    


poll和select的对比以及优缺点

优点:

  1. 它没有最大连接数的限制,因为底层是用链表实现的。
  2. poll() 在应付大数目的文件描述符的时候速度更快,相比于select
  3. poll将输入输出参数分离,不需要每次都重新设定。

缺点:

  1. 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
  2. 与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符

以上是关于TCP小型服务器(poll)的主要内容,如果未能解决你的问题,请参考以下文章

基于 Select Poll的TCP发服务器

基于 Select Poll的TCP发服务器

基于 Select Poll的TCP发服务器

Linux网络编程基于TCP流 I/O多路转接(poll) 的高性能http服务器

UNIX网络编程笔记—I/O复用select/poll

小型tcp服务器--select