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

  • 协议之间的关系

  • socket在哪

  • socket是什么

 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  门面模式,用自己的话说,就是系统对外界提供单一的接口,外部不需要了解内部的实现。

  • socket编程的基本流程

tcp通信实现多线程连接与群聊

服务器端

  • 定义端口以及本地ip地址
    1 #define port 9876
    2 #define ip_addr "192.168.1.102"
  • 创建事件以及互斥量

    1 HANDLE event;//事件
    2 HANDLE mutex = NULL;
    1 event = CreateEvent(NULL, TRUE, FALSE, NULL);//第二个参数TRUE表示手动复位
    2     mutex = CreateMutex(NULL, FALSE, NULL);//互相排斥
  • 接收连接

     1 //接受连接
     2 void recv_connect(void *p)
     3 {
     4     WSADATA WSA;//对比版本
     5 
     6     SOCKET client,sever;//客户端
     7 
     8     //本地地址信息,以及连接的客户端地址信息
     9     struct sockaddr_in localeaddr,clientaddr;
    10     int addrlength = 0;
    11     HANDLE hthread1 = NULL;//线程句柄
    12     HANDLE hthread2 = NULL;
    13     HANDLE hthread3 = NULL;
    14     int Ret = 0;
    15     char senbuf[256] = { 0 };
    16 
    17     //对比版本
    18     if (WSAStartup(MAKEWORD(2, 2), &WSA) != 0)
    19     {
    20         puts("版本不一致,通信失败");
    21         system("pause");
    22         return;
    23     }
    24     //创建通信
    25     sever = socket(AF_INET, SOCK_STREAM, 0);
    26     if (sever == INVALID_SOCKET)
    27     {
    28         puts("服务器创建失败");
    29         system("pause");
    30         return;
    31     }
    32     //设置服务器结构体信息
    33     localeaddr.sin_family = AF_INET;
    34     localeaddr.sin_addr.s_addr = inet_addr(ip_addr);
    35     localeaddr.sin_port = htons(port);
    36     memset(localeaddr.sin_zero, 0x00, 8);//清零
    37     //与socket绑定
    38     Ret = bind(sever, (struct sockaddr*)&localeaddr, sizeof(localeaddr));
    39     if (Ret != 0)
    40     {
    41         puts("绑定失败");
    42         system("pause");
    43         return;
    44     }
    45     Ret = listen(sever, 5);
    46     if (Ret != 0)
    47     {
    48         puts("监听失败");
    49         system("pause");
    50         return;
    51     }
    52     puts("服务器启动");
    53 
    54     while (1)
    55     {
    56         addrlength = sizeof(clientaddr);//获取长度
    57         //接受客户端连接,信息存放在clientaddr中
    58         client = accept(sever, (struct sockaddr*) &clientaddr, &addrlength);
    59         if (client == INVALID_SOCKET)
    60         {
    61             puts("接收失败");
    62             system("pause");
    63             return;
    64         }
    65         printf("
    客户端连接%s  端口号:%d
    ", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port);
    66         //创建写的线程
    67         hthread3 = CreateThread(NULL, 0, clientthreadwrite, (void*)client, 0, NULL);
    68     }
    69 
    70     //关闭socket
    71     closesocket(sever);
    72     closesocket(client);
    73     WSACleanup();
    74 }
  • 向客户端发送消息的多线程函数

     1 //创建线程向客户端发送消息
     2 DWORD WINAPI clientthreadwrite(void *p)
     3 {
     4     SOCKET client = (SOCKET)p;//数指针类型转换
     5     int Ret = 0;
     6 
     7     while (1)
     8     {
     9         WaitForSingleObject(event, INFINITE);//等待事件
    10         WaitForSingleObject(mutex, INFINITE);
    11         
    12         if (strlen(sendbuf) != 0)
    13         {
    14             //发送信息
    15             Ret = send(client, sendbuf, strlen(sendbuf), 0);
    16         }
    17         ReleaseMutex(mutex);
    18         ResetEvent(event);//手动复位
    19     }
    20 }
  • 从客户端接收消息的多线程函数

     1 DWORD WINAPI clientthreadread(void *p)
     2 {
     3     //数指针类型转换
     4     SOCKET client = (SOCKET)p;
     5     int Ret = 0;
     6     char receivebuf[256];
     7 
     8     while (1)
     9     {
    10         //清零
    11         memset(receivebuf, 0, 256);
    12         //读取
    13         Ret = recv(client, receivebuf, 256, 0);
    14         if (Ret == SOCKET_ERROR)
    15         {
    16             puts("客户端send失败");
    17             break;
    18         }
    19         printf("
    收到%s,", receivebuf);    
    20         //进入临界区
    21         WaitForSingleObject(mutex, INFINITE);
    22         memset(sendbuf, 0, 256);
    23         //全局变量,锁定
    24         strcpy(sendbuf, receivebuf);
    25         ReleaseMutex(mutex);
    26         //通知
    27         SetEvent(event);
    28     }
    29     return 0;
    30 }
      
  • main函数
     1 void main()
     2 {
     3     event = CreateEvent(NULL, TRUE, FALSE, NULL);//第二个参数TRUE表示手动复位
     4     mutex = CreateMutex(NULL, FALSE, NULL);//互相排斥
     5 
     6     _beginthread(recv_connect, 0, NULL);
     7 
     8     Sleep(100);
     9     while (1)
    10     {
    11         printf("请输入要发送的信息:");
    12         scanf("%s", sendbuf);
    13         SetEvent(event);
    14     }
    15     system("pause");
    16 }

客户端

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include <winsock.h>
 5 #pragma comment(lib,"ws2_32.lib")
 6 
 7 //定义端口号
 8 #define port 9876
 9 //要连接的ip地址
10 #define ip_addr "192.168.1.102"
11 
12 
13 void main()
14 {
15     //对比版本
16     WSADATA WSA;
17     //客户端套接字
18     SOCKET client;
19     //服务器信息
20     struct sockaddr_in severaddr;
21     //线程句柄
22     HANDLE hthread = NULL;
23     //保存连接信息
24     int Ret = 0;
25     char senbuf[256] = { 0 };
26 
27     if (WSAStartup(MAKEWORD(2,2),&WSA)!=0)
28     {
29         puts("版本不一致,通信失败");
30         system("pause");
31         return;
32     }
33     //创建socket
34     client = socket(AF_INET, SOCK_STREAM, 0);
35     if (client == INVALID_SOCKET)
36     {
37         puts("客户端创建失败");
38         system("pause");
39 
40     }
41     //设置服务器信息
42     severaddr.sin_family = AF_INET;
43     //设置地址
44     severaddr.sin_addr.s_addr = inet_addr(ip_addr);
45     //端口
46     severaddr.sin_port = htons(port);
47     //清空
48     memset(severaddr.sin_zero, 0x00, 8);
49 
50     //连接
51     Ret = connect(client, (struct sockaddr*) &severaddr, sizeof(severaddr));
52     if (Ret!=0)
53     {
54         puts("客户端链接失败");
55         system("pause");
56     }
57     while (1)
58     {
59         //printf("请输入向服务器发送的消息:");
60         //scanf("%s", senbuf);//输入
61         //Ret = send(client, senbuf, strlen(senbuf), 0);//发送
62         //if (Ret==SOCKET_ERROR)
63         //{
64         //    puts("客户端send失败");
65         //    system("pause");
66         //}
67         char receivebuf[256];
68         memset(receivebuf, 0, 256);//清零
69         Ret = recv(client, receivebuf, 256, 0);
70         printf("收到客户端发送的消息:%s
", receivebuf);
71     }
72 
73     closesocket(client);
74     WSACleanup();
75 }
原文地址:https://www.cnblogs.com/xiaochi/p/8482928.html