IO模型之epoll实现服务器客户端收发

 epoll.ser


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/epoll.h>

#define ERR_MSG(msg)                  \
	{                                 \
		printf("__%d__\n", __LINE__); \
		perror(msg);                  \
	}
#define IP "192.168.250.100"
#define PORT 12345

int main(int argc, const char *argv[])
{
	struct epoll_event event;
	struct epoll_event events[10]; // 存放就绪事件描述符的数组

	// 创建流式套接字
	int sfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket success\n");

	// 允许端口快速被复用
	int reuse = 1;
	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}

	// 绑定服务器的IP和端口
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);

	if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");

	// 将套接字设置为被动监听状态
	if (listen(sfd, 128) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");

	// 获取链接成功后的套接字,拿到文件描述符
	struct sockaddr_in cin;
	struct sockaddr_in savecin[1024];
	socklen_t len = sizeof(cin);
	char s[128] = "";
	char s1[128] = "";
	ssize_t res = 0;
	int num;
	int newfd, epfd;

	epfd = epoll_create(1);
	if (epfd < 0)
	{
		printf("epoll_create filed\n");
		exit(-1);
	}

	// 将套接字添加到红黑树
	event.events = EPOLLIN;
	event.data.fd = sfd;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &event) < 0)
	{
		printf("epoll_ctl add filed\n");
	}

	while (1)
	{
		int i;
		int ret = epoll_wait(epfd, events, 10, -1);
		if (ret < 0)
		{
			printf("epoll_wait filed\n");
			exit(-1);
		}

		for (i = 0; i < ret; i++)
		{
			if (events[i].data.fd == sfd) // 套接的文件描述符 来客户端了
			{
				newfd = accept(sfd, (struct sockaddr *)&cin, &len);
				if (newfd < 0)
				{
					ERR_MSG("accept");
					return -1;
				}
				bzero(s1, sizeof(s1));
				printf("客户端连接成功\n");

				savecin[newfd] = cin;
				// 添加准备就绪事件进入epoll;
				event.events = EPOLLIN; // 读事件
				event.data.fd = newfd;
				if (epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &event) < 0)
				{
					printf("epoll_ctl add filed\n");
				}
			}
			else
			{
				if (events[i].events & EPOLLIN)
				{
					int fd1 = events[i].data.fd;
					bzero(s, sizeof(s));
					res = recvfrom(events[i].data.fd, s, sizeof(s), 0, NULL, NULL);
					if (0 == res)
					{
						printf("客户端关闭\n");
						close(i);
						if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd1, &event) < 0)
						{
							printf("epoll_ctl sub filed\n");
						}
					}
					else if (res < 0)
					{
						ERR_MSG("recv");
						return -1;
					}
					printf("接收到的内容是:%s\n", s);
					printf("请输入要发送的内容:");

					scanf("%s", s1);
					if (write(events[i].data.fd, s1, sizeof(s1)) < 0)
					{
						ERR_MSG("write");
					}
					printf("发送成功\n");
				}
			}
		}
	}

	if (close(sfd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	return 0;
}

epoll.cri

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/epoll.h>

#define ERR(msg)                      \
	{                                 \
		printf("__%d__\n", __LINE__); \
		perror(msg);                  \
		return -1;                    \
	}
#define PORT 12345
#define IP "192.168.250.100"

int main(int argc, const char *argv[])
{
	
	//  创建套接字
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd < 0)
	{
		ERR("socket");
	}
	printf("socket success\n");

	// 连接服务器
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);
	socklen_t len = sizeof(sin);

	if (connect(fd, (struct sockaddr *)&sin, len) < 0)
	{
		ERR("connect");
	}
	printf("connect success\n");

	// 读取数据
	char s[128] = "";
	char s1[128] = "";
	ssize_t res = 0;
	int num;

	while (1)
	{
		printf("请输入要发送的内容:");
		
		scanf("%s", s1);
		if (write(fd, s1, sizeof(s1)) < 0)
		{
			ERR("write");
		}
		printf("发送成功\n");
		res = recvfrom(fd, s, sizeof(s), 0, NULL, NULL);
		printf("接收的内容:%s\n",s);
	}

	if (close(fd) < 0)
	{
		ERR("close");
	}

	return 0;
}

result

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你的问题是关于epoll客户端收发,我会尽力回答。以下是一个基于epoll客户端程序,可以实现收发功能: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/epoll.h> #define MAX_EVENTS 10 #define MAX_BUFFER_SIZE 1024 int main(int argc, char* argv[]) { if (argc != 3) { printf("usage: %s ip port\n", argv[0]); exit(1); } char* ip = argv[1]; int port = atoi(argv[2]); // 创建socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } // 连接服务器 struct sockaddr_in server_addr; 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)) < 0) { perror("connect error"); exit(1); } // 创建epoll句柄 int epfd = epoll_create(MAX_EVENTS); if (epfd < 0) { perror("epoll_create error"); exit(1); } // 注册sockfd到epoll句柄中 struct epoll_event ev; ev.events = EPOLLIN | EPOLLET; ev.data.fd = sockfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) < 0) { perror("epoll_ctl error"); exit(1); } // 创建缓冲区 char buffer[MAX_BUFFER_SIZE]; while (1) { // 等待事件的发生 struct epoll_event events[MAX_EVENTS]; int n = epoll_wait(epfd, events, MAX_EVENTS, -1); if (n < 0) { perror("epoll_wait error"); exit(1); } // 处理发生的事件 for (int i = 0; i < n; i++) { if (events[i].data.fd == sockfd) { if (events[i].events & EPOLLIN) { // 接收数据 int len = recv(sockfd, buffer, MAX_BUFFER_SIZE, 0); if (len < 0) { perror("recv error"); exit(1); } else if (len == 0) { printf("server closed\n"); exit(1); } else { buffer[len] = '\0'; printf("received: %s", buffer); } } else if (events[i].events & EPOLLOUT) { // 发送数据 printf("input message: "); fgets(buffer, MAX_BUFFER_SIZE, stdin); int len = send(sockfd, buffer, strlen(buffer), 0); if (len < 0) { perror("send error"); exit(1); } } } } } // 关闭socket close(sockfd); return 0; } ``` 该程序使用了epoll实现IO多路复用,可以同时处理接收和发送数据的操作。在程序中,先创建了一个socket并连接到服务器,然后创建了一个epoll句柄,并将socket注册到epoll句柄中。接下来进入循环,等待事件的发生,并处理发生的事件。当socket可读时,接收数据并输出;当socket可写时,从标准输入中读取数据并发送。当收到服务器关闭的消息时,程序退出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值