zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    实用的设计模式【一】---类设计法则
    vimium 使用心得
    记一次给部门做分享的心得
    centos7安装docker和docker compose【转】
    docker 部署 jenkins
    centos删除docker0虚拟网卡
    CentOS7查看和关闭防火墙
    .Net Core Autofac实现依赖注入
    【转】Docker基础
    【转】使用Docker+Jenkins自动构建部署
  • 原文地址:https://www.cnblogs.com/xiaochi/p/8482928.html
Copyright © 2011-2022 走看看