linux epoll send recv 实例
时间: 2023-10-13 15:24:50 浏览: 168
下面是一个使用 epoll 实现的简单的 TCP 服务器和客户端的例子。服务器和客户端都是非阻塞的,使用 epoll 监听和处理文件描述符事件。其中,服务器使用了多线程技术,每个线程负责处理一个客户端连接。
服务器代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <pthread.h>
#define MAX_EVENTS 1024
#define BUF_SIZE 1024
#define THREAD_NUM 4
int listen_fd;
int epoll_fd;
pthread_t thread_pool[THREAD_NUM];
void setnonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
void add_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
}
void del_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
}
void mod_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev);
}
void *worker(void *arg) {
int client_fd = *(int*)arg;
char buf[BUF_SIZE];
int nread;
while (1) {
nread = recv(client_fd, buf, BUF_SIZE, 0);
if (nread == -1) {
if (errno == EAGAIN) {
printf("recv EAGAIN\n");
break;
} else {
perror("recv");
break;
}
} else if (nread == 0) {
printf("client close\n");
break;
} else {
printf("recv: %s\n", buf);
if (send(client_fd, buf, nread, 0) == -1) {
perror("send");
break;
}
}
}
close(client_fd);
pthread_exit(NULL);
}
void *accepter(void *arg) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd;
int i;
while (1) {
client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
if (client_fd == -1) {
if (errno == EAGAIN) {
printf("accept EAGAIN\n");
continue;
} else {
perror("accept");
break;
}
} else {
setnonblocking(client_fd);
add_event(client_fd, EPOLLIN|EPOLLET);
printf("new client: %d\n", client_fd);
}
}
close(listen_fd);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
struct sockaddr_in server_addr;
int port = 8888;
struct epoll_event events[MAX_EVENTS];
int nready;
int i, j;
if (argc > 1) {
port = atoi(argv[1]);
}
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd == -1) {
perror("socket");
exit(1);
}
setnonblocking(listen_fd);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(1);
}
if (listen(listen_fd, 1024) == -1) {
perror("listen");
exit(1);
}
epoll_fd = epoll_create(MAX_EVENTS);
if (epoll_fd == -1) {
perror("epoll_create");
exit(1);
}
add_event(listen_fd, EPOLLIN|EPOLLET);
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_create(&thread_pool[i], NULL, accepter, NULL) == -1) {
perror("pthread_create");
exit(1);
}
}
while (1) {
nready = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nready == -1) {
if (errno == EINTR) {
continue;
} else {
perror("epoll_wait");
break;
}
}
for (i = 0; i < nready; i++) {
if (events[i].data.fd == listen_fd) {
continue;
}
if (events[i].events & EPOLLIN) {
pthread_t thread_id;
int client_fd = events[i].data.fd;
del_event(client_fd, EPOLLIN|EPOLLET);
if (pthread_create(&thread_id, NULL, worker, (void*)&client_fd) == -1) {
perror("pthread_create");
}
}
}
}
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_join(thread_pool[i], NULL) == -1) {
perror("pthread_join");
}
}
close(epoll_fd);
return 0;
}
```
客户端代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define MAX_EVENTS 1024
#define BUF_SIZE 1024
void setnonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
void add_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
}
void del_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev);
}
void mod_event(int fd, int events) {
struct epoll_event ev;
ev.events = events;
ev.data.fd = fd;
epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &ev);
}
int main(int argc, char *argv[]) {
struct sockaddr_in server_addr;
char *ip = "127.0.0.1";
int port = 8888;
int sockfd;
struct epoll_event events[MAX_EVENTS];
int nready;
char buf[BUF_SIZE];
int nread, nwrite;
int i;
if (argc > 1) {
ip = argv[1];
}
if (argc > 2) {
port = atoi(argv[2]);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(1);
}
setnonblocking(sockfd);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(ip);
server_addr.sin_port = htons(port);
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
if (errno != EINPROGRESS) {
perror("connect");
exit(1);
}
}
epoll_fd = epoll_create(MAX_EVENTS);
if (epoll_fd == -1) {
perror("epoll_create");
exit(1);
}
add_event(sockfd, EPOLLOUT);
while (1) {
nready = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nready == -1) {
if (errno == EINTR) {
continue;
} else {
perror("epoll_wait");
break;
}
}
for (i = 0; i < nready; i++) {
if (events[i].events & EPOLLOUT) {
del_event(sockfd, EPOLLOUT);
printf("connected\n");
break;
}
}
}
while (1) {
scanf("%s", buf);
if (strcmp(buf, "quit") == 0) {
break;
}
nwrite = send(sockfd, buf, strlen(buf), 0);
if (nwrite == -1) {
perror("send");
break;
}
nread = recv(sockfd, buf, BUF_SIZE, 0);
if (nread == -1) {
if (errno == EAGAIN) {
printf("recv EAGAIN\n");
continue;
} else {
perror("recv");
break;
}
} else if (nread == 0) {
printf("server close\n");
break;
} else {
printf("recv: %s\n", buf);
}
}
close(sockfd);
close(epoll_fd);
return 0;
}
```
阅读全文