104.tcp多线程读写实现群聊

客户端:

 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 (1)
17     {
18         printf("请输入发送的信息:
");
19         char str[256] = { 0 };
20         scanf("%s", str);
21         //发送
22         send(client, str, strlen(str), 0);
23         Sleep(100);
24     }
25 }
26 
27 void main()
28 {
29     //对比版本
30     WSADATA WSA;
31     //客户端套接字
32     SOCKET client;
33     //服务器地址
34     struct sockaddr_in severaddr;
35     int addrlength = 0;
36     HANDLE hthread = NULL;//线程句柄
37     int Ret = 0;;
38     char senbuf[256] = { 0 };
39 
40     //对比版本
41     if (WSAStartup(MAKEWORD(2,2),&WSA)!=0)
42     {
43         puts("版本不一致,通信失败");
44         system("pause");
45         return;
46     }
47     //创建socket通信
48     client = socket(AF_INET, SOCK_STREAM, 0);
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, 8);
63 
64     //连接到服务器
65     Ret = connect(client, (struct sockaddr*) &severaddr, sizeof(severaddr));
66     //判断是否连接成功
67     if (Ret!=0)
68     {
69         puts("客户端连接失败");
70         system("pause");
71     }
72     else
73     {
74         puts("客户端连接成功");
75     }
76 
77     //开启一个写的线程
78     _beginthread(write, 0, (void*)client);
79     //不断接收信息
80     while (1)
81     {
82         char receivebuf[256];
83         memset(receivebuf, 0, 256);//清零
84         Ret = recv(client, receivebuf, 256, 0);
85         if (strlen(receivebuf)>0)
86         {
87             printf("%s
", 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[256] = { 0 };
 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 = 0;
 36 
 37     //不断读取
 38     while (1)
 39     {
 40         //等待事件
 41         WaitForSingleObject(event, INFINITE);
 42         //创建互斥量
 43         WaitForSingleObject(mutex, INFINITE);
 44         //判断
 45         if (strlen(sendbuf)!=0)
 46         {
 47             Ret = send(client, sendbuf, strlen(sendbuf), 0);
 48             if (Ret == 0 || Ret == SOCKET_ERROR)
 49             {
 50                 //判断连接的客户端是否退出
 51                 printf("%s,%d退出
",inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
 52                 return;
 53             }
 54         }
 55         ReleaseMutex(mutex);
 56         ResetEvent(event);//手动复位
 57     }
 58     return 0;
 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 = 0;
 70     //接收到的信息
 71     char receivebufall[256] = {0};
 72     while (1)
 73     {
 74 
 75         char receivebuf[256] = { 0 };
 76         //接收
 77         Ret = recv(client, receivebuf, 256, 0);
 78         if (Ret == 0 ||Ret ==SOCKET_ERROR)
 79         {
 80             printf("%s,%d退出
", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
 81             return;
 82         }
 83 
 84         //收到
 85         if (strlen(receivebuf) > 0)
 86         {
 87             memset(receivebufall, 0, 256);
 88             sprintf(receivebufall, "收到%s:来自%s %d
", receivebuf, inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
 89             printf("%s", receivebufall);
 90         }
 91 
 92         //互斥量修改全局数据
 93         WaitForSingleObject(mutex, INFINITE);
 94         memset(sendbuf, 0, 256);
 95         strcpy(sendbuf, receivebufall);
 96         ReleaseMutex(mutex);
 97         //收到消息后设置事件,向所有客户端发送消息
 98         SetEvent(event);
 99     }
100     return 0;
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 = 0;
115     //线程句柄
116     HANDLE hthread = NULL;
117     //发送和接收消息的返回值
118     int Ret = 0;
119     char senbuf[256] = { 0 };
120 
121     //判断版本
122     if (WSAStartup(MAKEWORD(2, 2), &WSA) != 0)
123     {
124         puts("版本不一致,通信失败
");
125         system("pause");
126         return;
127     }
128     //创建服务器套接字
129     sever = socket(AF_INET, SOCK_STREAM, 0);
130     if (sever == INVALID_SOCKET)
131     {
132         puts("服务器创建失败
");
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, 8);//清零
141     //socket与sockaddr_in绑定
142     Ret = bind(sever, (struct sockaddr*)&localeaddr, sizeof(localeaddr));
143     if (Ret != 0)
144     {
145         puts("绑定失败");
146         system("pause");
147         return;
148     }
149     //开始监听
150     Ret = listen(sever, 5);
151     if (Ret != 0)
152     {
153         puts("监听失败");
154         system("pause");
155         return;
156     }
157     puts("服务器启动
");
158 
159     while (1)
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
", 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, 0, clientwrite, (void*)&pinfo, 0, NULL);
180         //开启一个读的线程
181         hthread = CreateThread(NULL, 0, clientthreadread, (void*)&pinfo, 0, NULL);
182     }
183 
184     closesocket(sever);
185     closesocket(client);
186     WSACleanup();
187 }
188 
189             
190 
191 void main()
192 {
193     event = CreateEvent(NULL, TRUE, FALSE, NULL);
194     mutex = CreateMutex(NULL, FALSE, NULL);//排斥
195     _beginthread(mains, 0, NULL);
196     while (1)
197     {    
198         printf("请输入向客户端发送的信息:");
199         scanf("%s", sendbuf);
200         SetEvent(event);
201     }
202 
203     system("pause");
204 }
原文地址:https://www.cnblogs.com/xiaochi/p/8488580.html