飞道的博客

TCP服务器连接多客户端(C语言实现)

229人阅读  评论(0)

目录

设计思路:

逻辑设计:

代码实现:

运行结果:


设计思路:

  • 在服务端客户端T一对一TCP的基础上增加几条通信即可,要求各个连接可同时进行通信因此使用多线程。
  • 主线程在listen实现后,使用一个 for 循环一直循环等待客户端的连接请求,将每次连接标记(sockFd)保存作为开启检测(检测条件可自行修改,我这个检测判断貌似也没起啥作用 也先不改了 (▼ヘ▼#),可以采用远端 IP 检查或者 IP+port 等方式来作为检测条件)。
  • 每次连接都会开启一个线程用于和客户端的通信(也是使用 for 循环进行数据的接收、处理、发送),数据接收使用阻塞等待。
  • 通信的具体实现,在开发板上部署运行下方的服务器端程序,客户端则在PC端网络调试助手开启多个port与服务器完成多个连接进行通信。

逻辑设计:

TCP服务器端逻辑设计

代码实现:


  
  1. #include <stdio.h>
  2. #include <sys/resource.h>
  3. #include <unistd.h>
  4. #include <pthread.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. /*********************************************************************************************************
  8. 宏定义
  9. *********************************************************************************************************/
  10. #define __TCP_ECHO_TYPE_CLIENT 1 /* 客户端模式 */
  11. #define __TCP_ECHO_TYPE_SERVER 2 /* 服务器模式 */
  12. #define __TCP_ECHO_TYPE (__TCP_ECHO_TYPE_SERVER) /* 当前模式选择 */
  13. #define __TCP_ECHO_IP_CLIENT "192.168.1.16" /* 客户端 IP 地址 */
  14. #define __TCP_ECHO_IP_SERVER "192.168.1.17" /* 服务器 IP 地址 */
  15. #define __TCP_ECHO_PORT_CLIENT 8100 /* 客户端端口号 */
  16. #define __TCP_ECHO_PORT_SERVER 8101 /* 服务器端口号 */
  17. #define __TCP_ECHO_BUFF_SIZE_CLIENT 257 /* 客户端接收缓冲区大小 */
  18. #define __TCP_ECHO_BUFF_SIZE_SERVER 257 /* 服务器接收缓冲区大小 */
  19. /*********************************************************************************************************
  20. ** 函数名称: 线程函数
  21. ** 功能描述: 为每个tcp连接开启一个线程 用于数据的接收、处理和发送
  22. ** 输 入 :
  23. ** 输 出 :
  24. ** 全局变量:
  25. ** 调用模块:
  26. *********************************************************************************************************/
  27. void * tcpThread(void * arg){
  28. int sockFd = *( int *)arg;
  29. char cRecvbuffer[__TCP_ECHO_BUFF_SIZE_SERVER]={ 0};
  30. ssize_t sstrRecv = 0;
  31. for(;;){
  32. memset(cRecvbuffer, 0, __TCP_ECHO_BUFF_SIZE_SERVER);
  33. sstrRecv = read(sockFd, ( void *)cRecvbuffer, __TCP_ECHO_BUFF_SIZE_SERVER);
  34. fprintf( stdout, "TCP server recive: %s\n",cRecvbuffer);
  35. if(sstrRecv <= 0){
  36. if((ETIMEDOUT != 0) && (EWOULDBLOCK != 0)){
  37. close(sockFd);
  38. fprintf( stderr, "TCP server bind error!\n");
  39. return ( void *)( -1);
  40. }
  41. continue;
  42. }
  43. write(sockFd, ( const void *)cRecvbuffer, sstrRecv);
  44. }
  45. }
  46. /*********************************************************************************************************
  47. ** 函数名称: main
  48. ** 功能描述: 主函数
  49. ** 输 入 : argc,argv
  50. ** 输 出 : ERROR
  51. ** 全局变量:
  52. ** 调用模块:
  53. *********************************************************************************************************/
  54. int main (int argc, char *argv[])
  55. {
  56. int sockFdConn[ 5]; /* 各客户端的套接口描述符 */
  57. int i, connTemp; /* 临时套接口描述符 */
  58. int connNum; /* 标记当前连接编号 */
  59. int sockFd = -1; /* 套接字描述符 */
  60. int iRet = -1; /* 返回值判断 */
  61. int connMax = -1; /* 连接的客户端总数 */
  62. pthread_t tid[ 5]; /* 线程句柄 */
  63. struct sockaddr_in sockaddrinRemote;
  64. struct sockaddr_in sockaddrinLocal;
  65. socklen_t size_sin = sizeof(struct sockaddr_in);
  66. sockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* 创建本地socket连接 */
  67. if(sockFd < 0){
  68. fprintf( stderr, "tcp server socket creat error!\n");
  69. return -1;
  70. }
  71. fprintf( stdout, "tcp server socket creat success!\n");
  72. /*
  73. * 初始化本地地址结构
  74. */
  75. memset(sockFdConn, -1, sizeof(sockFdConn));
  76. // memset(sockaddrinLocal, 0 ,sizeof(sockaddrinLocal));
  77. sockaddrinLocal.sin_len = sizeof(struct sockaddr_in);
  78. sockaddrinLocal.sin_family = AF_INET;
  79. sockaddrinLocal.sin_addr.s_addr = INADDR_ANY;
  80. sockaddrinLocal.sin_port = htons(__TCP_ECHO_PORT_SERVER);
  81. /*
  82. * 增加地址复用
  83. */
  84. iRet = setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &iRet, sizeof( int));
  85. if(iRet < 0){
  86. fprintf( stderr, "TCP reuseADDR error!\n");
  87. return -1;
  88. }
  89. /*
  90. * 绑定本地地址与端口
  91. */
  92. iRet = bind(sockFd, (struct sockaddr *)&sockaddrinLocal, sizeof(sockaddrinLocal));
  93. if(iRet < 0){
  94. fprintf( stderr, "TCP server bind error!\n");
  95. return -1;
  96. }
  97. fprintf( stdout, "TCP server bind success!\n");
  98. listen(sockFd, 5);
  99. fprintf( stdout, "TCP server bind listening ...\n");
  100. for(;;){
  101. // bzero(&sockaddrinRemote, sizeof(sockaddrinRemote));
  102. connTemp = accept(sockFd, (struct sockaddr *)&sockaddrinRemote, &size_sin);
  103. /* 同客户端创建连接 */
  104. fprintf( stdout, "RemoteAddr:%s, RemotePort:%hu\n", inet_ntoa(sockaddrinRemote.sin_addr),ntohs(sockaddrinRemote.sin_port));
  105. if(connTemp < 0){
  106. close(sockFd);
  107. fprintf( stderr, "TCP server accept error!\n");
  108. return -1;
  109. }
  110. /*
  111. * 检查当前连接是否存在(检查Fd不太合适,可自行修改)
  112. */
  113. for(i= 0; i<=connMax; i++){
  114. if(connTemp == sockFdConn[i]){
  115. connNum =i;
  116. break;
  117. }
  118. }
  119. if(i > connMax){
  120. connNum = ++connMax;
  121. sockFdConn[connNum]=connTemp;
  122. pthread_create(&tid[connNum], NULL, tcpThread, ( void*)&sockFdConn[connNum]);
  123. }
  124. // fprintf(stdout,"sockFdConn: %d\n",sockFdConn[cnt]);
  125. }
  126. close(sockFd);
  127. return 0;
  128. }
  129. /*********************************************************************************************************
  130. END
  131. *********************************************************************************************************/

运行结果:

多连接开启

 

程序进行中

转载:https://blog.csdn.net/Liangren_/article/details/116765272
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场