客户端:

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include <winsock.h>
  5. #include <process.h>
  6. #pragma comment(lib,"ws2_32.lib")
  7.  
  8. #define port 5529
  9. #define ip_addr "192.168.1.108"
  10.  
  11. //客户端写的线程
  12. void write(void *p)
  13. {
  14. //指针类型转换
  15. SOCKET client = (SOCKET)p;
  16. while ()
  17. {
  18. printf("请输入发送的信息:\n");
  19. char str[] = { };
  20. scanf("%s", str);
  21. //发送
  22. send(client, str, strlen(str), );
  23. Sleep();
  24. }
  25. }
  26.  
  27. void main()
  28. {
  29. //对比版本
  30. WSADATA WSA;
  31. //客户端套接字
  32. SOCKET client;
  33. //服务器地址
  34. struct sockaddr_in severaddr;
  35. int addrlength = ;
  36. HANDLE hthread = NULL;//线程句柄
  37. int Ret = ;;
  38. char senbuf[] = { };
  39.  
  40. //对比版本
  41. if (WSAStartup(MAKEWORD(,),&WSA)!=)
  42. {
  43. puts("版本不一致,通信失败");
  44. system("pause");
  45. return;
  46. }
  47. //创建socket通信
  48. client = socket(AF_INET, SOCK_STREAM, );
  49. if (client == INVALID_SOCKET)
  50. {
  51. puts("客户端创建失败");
  52. system("pause");
  53. }
  54. //设置服务器信息
  55. //协议族
  56. severaddr.sin_family = AF_INET;
  57. //设置地址
  58. severaddr.sin_addr.s_addr = inet_addr(ip_addr);
  59. //设置端口
  60. severaddr.sin_port = htons(port);
  61. //清空
  62. memset(severaddr.sin_zero, 0x00, );
  63.  
  64. //连接到服务器
  65. Ret = connect(client, (struct sockaddr*) &severaddr, sizeof(severaddr));
  66. //判断是否连接成功
  67. if (Ret!=)
  68. {
  69. puts("客户端连接失败");
  70. system("pause");
  71. }
  72. else
  73. {
  74. puts("客户端连接成功");
  75. }
  76.  
  77. //开启一个写的线程
  78. _beginthread(write, , (void*)client);
  79. //不断接收信息
  80. while ()
  81. {
  82. char receivebuf[];
  83. memset(receivebuf, , );//清零
  84. Ret = recv(client, receivebuf, , );
  85. if (strlen(receivebuf)>)
  86. {
  87. printf("%s\n", receivebuf);
  88. }
  89. }
  90.  
  91. //关闭客户端
  92. closesocket(client);
  93. WSACleanup();
  94. }

服务器端

  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include <winsock.h>
  5. #include <process.h>
  6. #pragma comment(lib,"ws2_32.lib")
  7.  
  8. //定义端口
  9. #define port 5529
  10. //设置本地ip
  11. #define ip_addr "169.254.29.232"
  12. //发送消息的缓存区
  13. char sendbuf[] = { };
  14. //事件
  15. HANDLE event=NULL;
  16. //创建互斥量
  17. HANDLE mutex = NULL;
  18.  
  19. //保存连接的客户端信息
  20. struct ipinfo
  21. {
  22. SOCKET client;//客户端
  23. struct sockaddr_in clientaddr;
  24. };
  25.  
  26. //读取线程是实时的,写入线程是有事件响应的,服务器输入或者收到消息则向客户端发送消息
  27.  
  28. //创建线程,用于向客户端发送信息
  29. DWORD WINAPI clientwrite(void *p)
  30. {
  31. //数指针类型转换
  32. SOCKET client = ((struct ipinfo*)p)->client;
  33. //获取连接的客户端信息
  34. struct sockaddr_in clientaddr = ((struct ipinfo*)p)->clientaddr;
  35. int Ret = ;
  36.  
  37. //不断读取
  38. while ()
  39. {
  40. //等待事件
  41. WaitForSingleObject(event, INFINITE);
  42. //创建互斥量
  43. WaitForSingleObject(mutex, INFINITE);
  44. //判断
  45. if (strlen(sendbuf)!=)
  46. {
  47. Ret = send(client, sendbuf, strlen(sendbuf), );
  48. if (Ret == || Ret == SOCKET_ERROR)
  49. {
  50. //判断连接的客户端是否退出
  51. printf("%s,%d退出\n",inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
  52. return;
  53. }
  54. }
  55. ReleaseMutex(mutex);
  56. ResetEvent(event);//手动复位
  57. }
  58. return ;
  59. }
  60.  
  61. //创建线程,用于读取客户端写入的信息
  62. DWORD WINAPI clientthreadread(void *p)
  63. {
  64. //数指针类型转换
  65. SOCKET client = ((struct ipinfo*)p)->client;
  66. //获取连接的客户端信息
  67. struct sockaddr_in clientaddr = ((struct ipinfo*)p)->clientaddr;
  68.  
  69. int Ret = ;
  70. //接收到的信息
  71. char receivebufall[] = {};
  72. while ()
  73. {
  74.  
  75. char receivebuf[] = { };
  76. //接收
  77. Ret = recv(client, receivebuf, , );
  78. if (Ret == ||Ret ==SOCKET_ERROR)
  79. {
  80. printf("%s,%d退出\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
  81. return;
  82. }
  83.  
  84. //收到
  85. if (strlen(receivebuf) > )
  86. {
  87. memset(receivebufall, , );
  88. sprintf(receivebufall, "收到%s:来自%s %d\n", receivebuf, inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
  89. printf("%s", receivebufall);
  90. }
  91.  
  92. //互斥量修改全局数据
  93. WaitForSingleObject(mutex, INFINITE);
  94. memset(sendbuf, , );
  95. strcpy(sendbuf, receivebufall);
  96. ReleaseMutex(mutex);
  97. //收到消息后设置事件,向所有客户端发送消息
  98. SetEvent(event);
  99. }
  100. return ;
  101. }
  102.  
  103. //创建线程
  104. //服务器
  105. void mains(void *p)
  106. {
  107. //对比版本
  108. WSADATA WSA;
  109. //客户端
  110. SOCKET client, sever;
  111. //服务器地址,和连接的客户端信息
  112. struct sockaddr_in localeaddr, clientaddr;
  113. //sockaddr_in的结构体大小
  114. int addrlength = ;
  115. //线程句柄
  116. HANDLE hthread = NULL;
  117. //发送和接收消息的返回值
  118. int Ret = ;
  119. char senbuf[] = { };
  120.  
  121. //判断版本
  122. if (WSAStartup(MAKEWORD(, ), &WSA) != )
  123. {
  124. puts("版本不一致,通信失败\n");
  125. system("pause");
  126. return;
  127. }
  128. //创建服务器套接字
  129. sever = socket(AF_INET, SOCK_STREAM, );
  130. if (sever == INVALID_SOCKET)
  131. {
  132. puts("服务器创建失败\n");
  133. system("pause");
  134. return;
  135. }
  136. //设置本地的sockaddr_in
  137. localeaddr.sin_family = AF_INET;
  138. localeaddr.sin_addr.s_addr = inet_addr(ip_addr);
  139. localeaddr.sin_port = htons(port);
  140. memset(localeaddr.sin_zero, 0x00, );//清零
  141. //socket与sockaddr_in绑定
  142. Ret = bind(sever, (struct sockaddr*)&localeaddr, sizeof(localeaddr));
  143. if (Ret != )
  144. {
  145. puts("绑定失败");
  146. system("pause");
  147. return;
  148. }
  149. //开始监听
  150. Ret = listen(sever, );
  151. if (Ret != )
  152. {
  153. puts("监听失败");
  154. system("pause");
  155. return;
  156. }
  157. puts("服务器启动\n");
  158.  
  159. while ()
  160. {
  161. //获取长度
  162. addrlength = sizeof(clientaddr);
  163. //通过套接字接受客户端连接
  164. client = accept(sever, (struct sockaddr*) &clientaddr, &addrlength);
  165. if (client == INVALID_SOCKET)
  166. {
  167. puts("接收失败");
  168. system("pause");
  169. return;
  170. }
  171. printf("客户端连接%s %d\n", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
  172.  
  173. //全局变量pinfo只是起到一个中转的作用,最后结果存放在线程里面
  174. //创建连接的客户端信息
  175. struct ipinfo pinfo;
  176. pinfo.client = client;
  177. pinfo.clientaddr = clientaddr;
  178. //开启一个写的线程
  179. hthread = CreateThread(NULL, , clientwrite, (void*)&pinfo, , NULL);
  180. //开启一个读的线程
  181. hthread = CreateThread(NULL, , clientthreadread, (void*)&pinfo, , NULL);
  182. }
  183.  
  184. closesocket(sever);
  185. closesocket(client);
  186. WSACleanup();
  187. }
  188.  
  189. void main()
  190. {
  191. event = CreateEvent(NULL, TRUE, FALSE, NULL);
  192. mutex = CreateMutex(NULL, FALSE, NULL);//排斥
  193. _beginthread(mains, , NULL);
  194. while ()
  195. {
  196. printf("请输入向客户端发送的信息:");
  197. scanf("%s", sendbuf);
  198. SetEvent(event);
  199. }
  200.  
  201. system("pause");
  202. }

104.tcp多线程读写实现群聊的更多相关文章

  1. 102.tcp实现多线程连接与群聊

    协议之间的关系 socket在哪 socket是什么 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP ...

  2. Java 网络编程 -- 基于TCP 实现聊天室 群聊 私聊

    分析: 聊天室需要多个客户端和一个服务端. 服务端负责转发消息. 客户端可以发送消息.接收消息. 消息分类: 群聊消息:发送除自己外所有人 私聊消息:只发送@的人 系统消息:根据情况分只发送个人和其他 ...

  3. Android 基于TCP多线程通信实现群聊天的功能

    1.TCP多线程原理图 2.实现方法 (1)服务器端 (2)客户端 3.java后台代码 主界面 package com.lucky.test50socket2; import android.ann ...

  4. TCP多线程聊天室

    TCP协议,一个服务器(ServerSocket)只服务于一个客户端(Socket),那么可以通过ServerSocket+Thread的方式,实现一个服务器服务于多个客户端. 多线程服务器实现原理— ...

  5. C/S模型之TCP群聊

    说明:利用TCP协议和多线程实现群聊功能.一个服务器,多个客户端(同一个程序多次启动).客户端向服务端发送数据,由服务端进行转发到其他客户端. /服务端 // WSASever.cpp : 定义控制台 ...

  6. Java-->实现群聊功能(C/S模式--TCP协议)

    --> Java 对TCP协议的支持: --> java.net包中定义了两个类ServerSocket 和Socket ,分别用来实现双向连接的server 端和client 端. -- ...

  7. [Python 网络编程] TCP编程/群聊服务端 (二)

    群聊服务端 需求分析: 1. 群聊服务端需支持启动和停止(清理资源); 2. 可以接收客户端的连接; 接收客户端发来的数据 3. 可以将每条信息分发到所有客户端 1) 先搭架子: #TCP Serve ...

  8. java基于socket的网络通信,实现一个服务端多个客户端的群聊,传输文件功能,界面使用Swing

    最近在复习java的io流及网络编程.但复习写那些样板程序总是乏味的.便准备写个项目来巩固.想来想去还是聊天项目比较好玩.如果日后完成的比较好自己也可以用(哈哈哈).并且自己后面也要继续巩固java多 ...

  9. 一套高可用、易伸缩、高并发的IM群聊架构方案设计实践

    本文原题为“一套高可用群聊消息系统实现”,由作者“于雨氏”授权整理和发布,内容有些许改动,作者博客地址:alexstocks.github.io.应作者要求,如需转载,请联系作者获得授权. 一.引言 ...

随机推荐

  1. 一张图了解javaJwt

    1.什么是javaJwt? JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims ...

  2. [工具] UltraEdit使用技巧汇总

    ltraEdit是一套功能强大的文本编辑器,可以编辑文本.十六进制.ASCII码,可以取代记事本,内建英文单字检查.C++及VB指令突显,可同时编辑多个文件,而且即使开启很大的文件速度也不会慢.说到编 ...

  3. mysql安装遇到的坑

    安装mysql的三步: mysqld --initialize-insecure mysqld -install net start mysql 中间遇到了坑, 看这篇文章完美的解决了,记录一下 .以 ...

  4. SpringMVC与SpringBoot返回静态页面遇到的问题

    1.SpringMVC静态页面响应 package com.sv.controller; import org.springframework.stereotype.Controller; impor ...

  5. 23种JavaScript设计模式

    原文链接:https://boostlog.io/@sonuton/23-javascript-design-patterns-5adb006847018500491f3f7f 转自: https:/ ...

  6. 使用 HTML5 canvas制作拾色器

    自制的拾色器漂亮吧,哈哈 废话不多说直接上代码,希望可以帮到需要的朋友 <html><head>    <style>        .canvas_color{p ...

  7. 【Henu ACM Round#15 E】 A and B and Lecture Rooms

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 最近公共祖先. (树上倍增 一开始统计出每个子树的节点个数_size[i] 如果x和y相同. 那么直接输出n. 否则求出x和y的最近 ...

  8. MySQL架构组成之逻辑模块组成

    MySQL 能够看成是二层架构   第一层SQL Layer.包含权限推断.sql 解析.运行计划优化,query cache 的处理等等.   第二层存储引擎层(Storage Engine Lay ...

  9. ChinaVis2015 第一天会议

    第二届  ChinaVis 2015 在天津举行,非常幸运发现者个会议,并在导师的带领下參与本次会议. 主要要是以可视化与可视分析为背景进行讲座,以马匡六为Speaker.袁晓如,张加万等致辞开幕式. ...

  10. 【java】itoo项目实战之大数据查询之使用 new map 优化hibernate之级联查询

    在我的上一篇博客<[java]itoo项目实战之hibernate 懒载入优化性能>中,我曾提到过学生数据有2万条,查询数据十分的慢,这是让人非常受不了的事情.看着页面进度条一直转着圈圈, ...