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++;
}
}
第一次写博客写的比较糟,如果大家对代码有问题的话可以在下面留言,我会及时进行回复的