#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define MAX_EVENTS 10
#define BUFFER_SIZE 1024
#define PORT 8888
void set_nonblocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
int main() {
int tcp_sock, udp_sock, epoll_fd;
struct epoll_event ev, events[MAX_EVENTS];
// 创建TCP套接字
if ((tcp_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("TCP socket");
exit(EXIT_FAILURE);
}
// 创建UDP套接字
if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("UDP socket");
close(tcp_sock);
exit(EXIT_FAILURE);
}
// 设置地址重用
int opt = 1;
setsockopt(tcp_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(udp_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(PORT)
};
// 绑定TCP
if (bind(tcp_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("TCP bind");
close(tcp_sock);
close(udp_sock);
exit(EXIT_FAILURE);
}
// 绑定UDP
if (bind(udp_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("UDP bind");
close(tcp_sock);
close(udp_sock);
exit(EXIT_FAILURE);
}
// 监听TCP
if (listen(tcp_sock, SOMAXCONN) == -1) {
perror("TCP listen");
close(tcp_sock);
close(udp_sock);
exit(EXIT_FAILURE);
}
// 创建epoll实例
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1");
close(tcp_sock);
close(udp_sock);
exit(EXIT_FAILURE);
}
// 添加TCP到epoll
ev.events = EPOLLIN;
ev.data.fd = tcp_sock;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tcp_sock, &ev);
// 添加UDP到epoll(非阻塞)
set_nonblocking(udp_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = udp_sock;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, udp_sock, &ev);
printf("Server started on TCP/UDP port %d\n", PORT);
while (1) {
int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
break;
}
for (int i = 0; i < nfds; ++i) {
if (events[i].data.fd == tcp_sock) {
// 处理TCP连接
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
int conn_sock = accept(tcp_sock, (struct sockaddr*)&client_addr, &addrlen);
if (conn_sock == -1) {
perror("TCP accept");
continue;
}
set_nonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_sock, &ev);
printf("New TCP connection: %d\n", conn_sock);
}
else if (events[i].data.fd == udp_sock) {
// 处理UDP数据
struct sockaddr_in client_addr;
socklen_t addrlen = sizeof(client_addr);
char buffer[BUFFER_SIZE];
while (1) {
ssize_t bytes_recv = recvfrom(udp_sock, buffer, BUFFER_SIZE, 0,
(struct sockaddr*)&client_addr, &addrlen);
if (bytes_recv <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) break;
perror("UDP recv");
break;
}
printf("Received %zd UDP bytes\n", bytes_recv);
sendto(udp_sock, buffer, bytes_recv, 0,
(struct sockaddr*)&client_addr, addrlen);
}
}
else {
// 处理TCP客户端数据
char buffer[BUFFER_SIZE];
ssize_t bytes_read;
int fd = events[i].data.fd;
while ((bytes_read = read(fd, buffer, BUFFER_SIZE)) > 0) {
write(fd, buffer, bytes_read);
}
if (bytes_read == 0 || (bytes_read == -1 && errno != EAGAIN)) {
printf("TCP connection closed: %d\n", fd);
close(fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
}
}
}
}
close(tcp_sock);
close(udp_sock);
close(epoll_fd);
return 0;
}
查看端口的时候我发现并不冲突,UDP是无连接的因此不会有listen和established这种状态。