2.4 linux利用Socket套接字一个服务器向多个客户端群发消息(实验二)
2018-01-19 17:15
399 查看
-------------------下面代码来源于网上,本人仅测试和修改,并未做其他改变
在测试过程中发现,记录如下:
这个是可以用的,亲测成功,很高兴!
============================================================================
代码如下
功能:一个服务器连接多个客户端,向客户端群发消息
============================================================================
服务器端代码如下:
客户端代码如下:
测试流程如下:
1. 2个客户端接入
虚拟机和网络调试助手软件 接入 服务器端 如下:
2. 服务器群发消息
在测试过程中发现,记录如下:
1.客户端初始化 一次Socket 连上服务器,如果此时连不上,就要重启才能连上(待优化) | |
2.客户端发数据给服务器, 命令行 显示的数据不完整,收到消息凌乱(待优化) | |
============================================================================
代码如下
功能:一个服务器连接多个客户端,向客户端群发消息
============================================================================
服务器端代码如下:
#include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <sys/socket.h> #include <string.h> # 4000 include <signal.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> //服务器端 void *fun_thrReceiveHandler(void *socketInfo); void *fun_thrAcceptHandler(void *socketListen); //1:是 0:否 int checkThrIsKill(pthread_t thr); typedef struct MySocketInfo{ int socketCon; char *ipaddr; uint16_t port; }_MySocketInfo; // 客户端数组 struct MySocketInfo arrConSocket[10]; int conClientCount = 0; // 接受客户端线程列表 pthread_t arrThrReceiveClient[10]; int thrReceiveClientCount = 0; int main() { //初始化全局变量 //memset(arrConSocket,0,sizeof(struct MySocketInfo)*10); printf("开始socket\n"); /* 创建TCP连接的Socket套接字 */ int socketListen = socket(AF_INET, SOCK_STREAM, 0); if(socketListen < 0){ printf("创建TCP套接字失败\n"); exit(-1); }else{ printf("创建套接字成功\n"); } /* 填充服务器端口地址信息,以便下面使用此地址和端口监听 */ struct sockaddr_in server_addr; bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); /* 这里地址使用全0,即所有 */ server_addr.sin_port=htons(5566); if(bind(socketListen, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) != 0){ perror("绑定ip地址、端口号失败\n"); exit(-1); }else{ printf("绑定ip地址,端口号\n"); } /* 开始监听相应的端口 */ if(listen(socketListen, 10) != 0){ printf("开启监听失败\n"); exit(-1); }else{ printf("开启监听成功\n"); } /* 接受连接套接字 */ pthread_t thrAccept; pthread_create(&thrAccept,NULL,fun_thrAcceptHandler,&socketListen); /* 实时发送数据 */ while(1){ //判断线程存活多少 int i; for(i=0;i<thrReceiveClientCount;i++){ if(checkThrIsKill(arrThrReceiveClient[i]) == 1){ printf("有个线程被杀了\n"); thrReceiveClientCount--; } } printf("当前有接受数据线程多少个:%d\n",thrReceiveClientCount); // 可以录入用户操作选项,并进行相应操作 char userStr[30] = {'0'}; scanf("%s",userStr); if(strcmp(userStr,"q") == 0){ printf("用户选择退出!\n"); break; } // 发送消息,一个服务器向多个客户端群发消息(核心) if(conClientCount <= 0){ printf("没有客户端连接\n"); }else{ int i; for(i=0; i<conClientCount; i++){ //int sendMsg_len = send(arrConSocket[i].socketCon, userStr, 30, 0); int sendMsg_len = write(arrConSocket[i].socketCon,userStr,30); if(sendMsg_len > 0){ printf("向%s:%d发送成功\n",arrConSocket[i].ipaddr,arrConSocket[i].port); }else{ printf("向%s:%d发送失败\n",arrConSocket[i].ipaddr,arrConSocket[i].port); } } } sleep(0.5); } // 等待子进程退出 printf("等待子线程退出,即将退出!\n"); char *message; pthread_join(thrAccept,(void *)&message); printf("%s\n",message); return 0; } void *fun_thrAcceptHandler(void *socketListen){ while(1){ int sockaddr_in_size = sizeof(struct sockaddr_in); struct sockaddr_in client_addr; int _socketListen = *((int *)socketListen); int socketCon = accept(_socketListen, (struct sockaddr *)(&client_addr), (socklen_t *)(&sockaddr_in_size)); if(socketCon < 0){ printf("连接失败\n"); }else{ printf("连接成功 ip: %s:%d\r\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port); } printf("连接套接字为:%d\n",socketCon); //开启新的通讯线程,负责同连接上来的客户端进行通讯 _MySocketInfo socketInfo; socketInfo.socketCon = socketCon; socketInfo.ipaddr = inet_ntoa(client_addr.sin_addr); socketInfo.port = client_addr.sin_port; arrConSocket[conClientCount] = socketInfo; conClientCount++; printf("连接了%d个用户\n",conClientCount); pthread_t thrReceive = 0; pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketInfo); arrThrReceiveClient[thrReceiveClientCount] = thrReceive; thrReceiveClientCount++; //让进程休息1秒 sleep(0.5); } char *s = "安全退出接受进程"; pthread_exit(s); } void *fun_thrReceiveHandler(void *socketInfo){ char buffer[30]; int buffer_length; _MySocketInfo _socketInfo = *((_MySocketInfo *)socketInfo); while(1){ //添加对buffer清零 bzero(&buffer,sizeof(buffer)); buffer_length = read(_socketInfo.socketCon,buffer,30); if(buffer_length == 0){ printf("%s:%d 客户端关闭\n",_socketInfo.ipaddr,_socketInfo.port); conClientCount--; break; }else if(buffer_length < 0){ printf("接受客户端数据失败\n"); break; } buffer[buffer_length] = '\0'; printf("%s:%d 说:%s\n",_socketInfo.ipaddr,_socketInfo.port,buffer); sleep(0.2); } printf("接受数据线程结束了\n"); return NULL; } int checkThrIsKill(pthread_t thr){ int res = 1; int res_kill = pthread_kill(thr,0); if(res_kill == 0){ res = 0; } return res; }===============================================================================
客户端代码如下:
#include <stdlib.h> #include <sys/types.h> #include <stdio.h> #include <sys/socket.h> #include <string.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> typedef struct MySocketInfo{ int socketCon; unsigned long ipaddr; unsigned short port; }_MySocketInfo; void *fun_thrReceiveHandler(void *socketCon); int checkThrIsKill(pthread_t thr); int main() { printf("开始socket\n"); /* 创建TCP连接的Socket套接字 */ int socketCon = socket(AF_INET, SOCK_STREAM, 0); if(socketCon < 0){ printf("创建TCP连接套接字失败\n"); exit(-1); } /* 填充客户端端口地址信息,以便下面使用此地址和端口监听 */ struct sockaddr_in server_addr; bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); /* 这里地址使用全0,即所有 */ server_addr.sin_port=htons(2000); /* 连接服务器 */ int res_con = connect(socketCon,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)); if(res_con != 0){ printf("连接失败\n"); exit(-1); } printf("连接成功,连接结果为:%d\n",res_con); //开启新的实时接受数据线程 pthread_t thrReceive; pthread_create(&thrReceive,NULL,fun_thrReceiveHandler,&socketCon); /* 实时发送数据 */ while(1){ //检测接受服务器数据线程是否被杀死 char userStr[30] = {'0'}; // 可以录入用户操作选项,并进行相应操作 scanf("%s",userStr); if(strcmp(userStr,"q") == 0){ printf("用户选择退出!\n"); break; } // 发送消息 //int sendMsg_len = send(socketCon, userStr, 30, 0); int sendMsg_len = write(socketCon,userStr,30); if(sendMsg_len > 0){ printf("发送成功,服务端套接字句柄:%d\n",socketCon); }else{ printf("发送失败\n"); } //if(checkThrIsKill(thrReceive) == 1){ //printf("接受服务器数据的线程已被关闭,退出程序\n"); //break; //} } // 关闭套接字 close(socketCon); return 0; } void *fun_thrReceiveHandler(void *socketCon){ while(1){ char buffer[30]; int _socketCon = *((int *)socketCon); //int buffer_length = recv(_socketCon,buffer,30,0); int buffer_length = read(_socketCon,buffer,30); if(buffer_length == 0){ printf("服务器端异常关闭\n"); exit(-1); }else if(buffer_length < 0){ printf("接受客户端数据失败\n"); break; } buffer[buffer_length] = '\0'; printf("服务器说:%s\n",buffer); } printf("退出接受服务器数据线程\n"); return NULL; } int checkThrIsKill(pthread_t thr){ int res = 1; int res_kill = pthread_kill(thr,0); if(res_kill == 0){ res = 0; } return res; }================================================================================
测试流程如下:
1. 2个客户端接入
虚拟机和网络调试助手软件 接入 服务器端 如下:
2. 服务器群发消息
相关文章推荐
- 2.5 Linux下的Socket编程-多个客户端之间的消息通讯(实验三)
- Java 利用套接字Socket实现简单的服务器与客户端通信
- Linux C利用Socket套接字进行服务器与多个客户端进行通讯
- Java 利用套接字Socket实现简单的服务器与客户端通信
- Linux C语言编程-Linux网络通信--Linux上使用套接字(socket)来处理信息---编写一个单进程非阻塞多客户的套接字客户端
- linux下socket编程实现一个服务器连接多个客户端
- TCP/TP编程 - 一个简单的Linux下C写的socket服务器客户端程序
- linux下socket编程实现一个服务器连接多个客户端
- Linux C利用Socket套接字进行服务器与多个客户端进行通讯
- Java_socket程序学习01-一个客户端对一个服务器
- Java_socket程序学习03-一个客户端对一个服务器-交互(服务器端)--01
- linux udp协议服务器,客户端socket使用
- 使用socket模拟服务器给客户端发消息
- 利用Python中SocketServer 实现客户端与服务器间非阻塞通信
- Linux Socket 事件触发模型 epoll 示例 这里会写一个用C语言的TCP服务器的完全实现的简单程序
- 【实验 1-1】编写一个简单的 TCP 服务器和 TCP 客户端程序。程序均为控制台程序窗口。
- 使用socket的Linux上的C语言helloworld多线程服务器和客户端测试程序
- 利用C#进行socket编程(模拟服务器和客户端通信)
- LINUX利用多线程完成多个客户端向服务器发送数据
- 利用Flash作为桥梁连接WEB页面和服务器端Socket通信,达到服务器主动"推"客户端的效果