linux socket编程epoll模型实现群发消息

 1.实现功能

  本代码主要实现了socket编程epoll模型实现多个客户端连接服务器,客户端可以进行群发消息和接收用户输入文本信息,然后发送该信息给服务器,服务器收到后发送应答信息。客户端接收并显示该应答信息,文章的后面会附上完整代码哦!

1.1

服务器使用epoll模型,支持多个客户端同时连接。

 多个客户端同时连接

实现代码:

实现功能:客户端输入3333给服务器后服务器对客户端进行应答返回3333

 实现代码

 上线的客户端会存放到客户容器中,发送数据时会对这些客户端描述符都进行发送

实现功能:输入user会获取到所有的在线客户端的文件描述符

 

实现代码

实现功能:客户端输入exit或ctrl+c后退出该客户端

实现代码

 

 输入事件判断如果没有接收到数据说明按下ctrl+c了,所以进行清除该文件描述符

 输入exit也一致

客户端代码

#include<sys/types.h>
#include <sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <pthread.h>
int socket_fd;
char buff[1024];
void* pthread_fun(void* arg)
{

	while (1)
	{
		memset(buff, 0, 1024);
		fgets(buff, sizeof(buff), stdin);
		write(socket_fd, buff, strlen(buff));
		if (strncmp(buff, "exit", 4) == 0)
		{
			break;
		}
	}
}
int main()
{
	int num;
	int count = 0;
	char buff1[1024];
	struct sockaddr_in server_addr;
	int clientlist[1024];
	int i = 0;

	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;//IPV4
	server_addr.sin_port = htons(8888);
	inet_aton("127.0.0.1", &server_addr.sin_addr);
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_fd == -1)
	{
		printf("socket error %s\n", strerror(errno));
		exit(-1);
	}

	if (connect(socket_fd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)) == -1)
	{
		printf("connect error %s\n", strerror(errno));
		exit(-1);
	}
	printf("connect success\n");
	pthread_t thread;
	int res;
	res = pthread_create(&thread, NULL, pthread_fun, NULL);

	if (res != 0)
	{
		printf("pthread_create error:%s\n", strerror(res));
	}
	while (true)
	{
		memset(buff,0,sizeof(buff));
		read(socket_fd,buff,sizeof(buff));
		if (strncmp(buff, "exit", 4) == 0)
		{
			break;
		}
		else if (strncmp(buff, "user", 4) == 0)
		{

			memset(buff1, 0, sizeof(buff1));
			count = 0;
			read(socket_fd, clientlist, sizeof(clientlist));
			printf("client list\n");
			for (i = 0; i < 1024; i++)
			{
				if (clientlist[i] != 0)
				{
					memset(buff1, 0, sizeof(buff1));
					count++;
					sprintf(buff1, "client%d", clientlist[i]);
					printf("%d:%s\n",count,buff1);
				}
			}
			//printf("client list\n");
			//for (i = 0; clientlist[i]; i++)
			//{
			//	memset(buff1, 0, sizeof(buff1));
			//	count++;
			//	sprintf(buff1, "client%d", clientlist[i]);
			//	printf("%d:%s\n",count,buff1);
			//}
			//for (map<int, string>::iterator it = client_map.begin(); it != client_map.end(); it++)
			//{
			//	memset(buff1, 0, sizeof(buff1));
			//	count++;
			//	//sprintf(buff1, "client%d", it->first);
			//	printf("%d\n",count);
			//}

		}
		else
		{
			printf("%s\n", buff);
		}
		

	}
	close(socket_fd);

	return 0;
}

 服务器代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <map>
#include <string>
using namespace std;
map<int, string> client_map;
int count = 0;
int clientlist[1024] = { 0 };
void handle_accept(int epollfd, int socket_fd);
int main()
{
	int i;
	int res;
	struct sockaddr_in server_addr;
	int socket_fd;
	
	socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (socket_fd == -1)
	{
		printf("socket error:%s", strerror(errno));
		exit(1);
	}

	//设置地址重用
	int opt;
	if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)) < 0)
	{
		perror("setsockopt\n");
		close(socket_fd);
		exit(1);
	}
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = INADDR_ANY;
	server_addr.sin_port = htons(8888);
	res = bind(socket_fd, (const sockaddr*)&server_addr, sizeof(struct sockaddr_in));
	if (res == -1)
	{
		printf("bind error:%s", strerror(errno));
		exit(1);
	}
	res = listen(socket_fd, 1024);
	if (res == -1)
	{
		printf("listen error:%s", strerror(errno));
		exit(1);
	}

	//epoll流程
	int epollfd;
	int ret;
	epollfd = epoll_create(1500);
	struct epoll_event event;
	
	event.events = EPOLLIN;
	event.data.fd = socket_fd;
	//添加监听文件描述符事件
	epoll_ctl(epollfd, EPOLL_CTL_ADD, socket_fd, &event);
	int fd;
	while (1)
	{
		struct epoll_event events[100];
		//查询就绪表 获取已经就绪的事件
		ret=epoll_wait(epollfd, events, 100, -1);
		printf("ret=%d\n", ret);
		for (i = 0; i < ret; i++)
		{
			fd = events[i].data.fd;
			if ((fd == socket_fd) && (events[i].events & EPOLLIN))
			{

				handle_accept(epollfd, socket_fd);
				continue;
			}
			else if (events[i].events & EPOLLIN)
			{
				int num;
				char buff[1024];
				char buff1[1024];
				//输入事件
				memset(buff, 0, sizeof(buff));
				memset(buff1, 0, sizeof(buff1));
				num=read(events[i].data.fd, buff, sizeof(buff));
				if (num <= 0)
				{
					memset(&event, 0, sizeof(struct epoll_event));
					event.events = EPOLLIN;
					event.data.fd = events[i].data.fd;
					epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
					close(events[i].data.fd);
					client_map.erase(events[i].data.fd);
					continue;
				}
				else
				{
					if (strncmp(buff,"exit",4) == 0)
					{
						write(events[i].data.fd, buff, sizeof(buff));
						memset(&event, 0, sizeof(struct epoll_event));
						event.events = EPOLLIN;
						event.data.fd = events[i].data.fd;
						epoll_ctl(epollfd, EPOLL_CTL_DEL, events[i].data.fd, &event);
						close(events[i].data.fd);
						client_map.erase(events[i].data.fd);
						clientlist[events[i].data.fd-5] = 0;
						continue;
					}
					else if(strncmp(buff, "user", 4) == 0)
					{
						//for (int i = 0; i < 1024; i++)
						//{
						//	clientlist[i] = 0;
						//}
						write(events[i].data.fd, buff, sizeof(buff));
						i = 0;
						//for (map<int, string>::iterator it = client_map.begin(); it != client_map.end(); it++)
						//{
						//	clientlist[i] = it->first;
						//	i++;
						//	printf("i=%d\n", i);
						//}
						/*printf("it->first=%d\n", clientlist[0]);*/
						write(events[i].data.fd, clientlist , sizeof(clientlist));
						continue;
					}
					else
					{
						for (map<int, string>::iterator it = client_map.begin(); it != client_map.end(); it++)
						{
							sprintf(buff1, "receive client%d content:%s", events[i].data.fd, buff);
							write(it->first, buff1, sizeof(buff1));
						}
					}


				}
				continue;
			}
		}

	}
	close(epollfd);
	close(socket_fd);
	return 0;
}
void handle_accept(int epollfd, int socket_fd)
{
	struct epoll_event ev;
	socklen_t len;
	struct sockaddr_in client_addr;
	int new_fd;
	len = sizeof(struct sockaddr);
	new_fd = accept(socket_fd, (struct sockaddr*)(&client_addr), &len);
	printf("1111\n");
	if (new_fd == -1)
	{
		printf("accept error:%s", strerror(errno));
		exit(1);
	}
	else
	{
		printf("new_fd: %d IP:%s PORT %d\n", new_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
		//添加来自客户端的描述符和事件
		ev.data.fd = new_fd;
		ev.events = EPOLLIN;
		epoll_ctl(epollfd, EPOLL_CTL_ADD, new_fd, &ev);
		//添加到用户上线容器中
		char str[80];
		sprintf(str, "clinet%d", count);
		client_map.insert(pair<int,string>(new_fd,str));
		clientlist[count] = new_fd;
		count++;
	}
}

第一次写博客写的比较糟,如果大家对代码有问题的话可以在下面留言,我会及时进行回复的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值