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的对比以及优缺点
优点:
- 它没有最大连接数的限制,因为底层是用链表实现的。
- poll() 在应付大数目的文件描述符的时候速度更快,相比于select
- poll将输入输出参数分离,不需要每次都重新设定。
缺点:
- 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
- 与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
以上是关于TCP小型服务器(poll)的主要内容,如果未能解决你的问题,请参考以下文章