专栏首页前端儿【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 "多人聊天室"

【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 "多人聊天室"

本次实验利用TCP/IP, 语言环境为 C/C++

利用套接字Socket编程,以及线程处理,

实现Server/CLient 之间多人的聊天系统的基本功能。

结果大致如:

下面贴上代码(参考参考...)

Server 部分:

  1 /* TCPdtd.cpp - main, TCPdaytimed */
  2 
  3 #include <stdlib.h>
  4 #include <stdio.h>
  5 #include <winsock2.h>
  6 #include <time.h>
  7 #include "conio.h"
  8 #include <windows.h>
  9 #include <process.h>
 10 #include <math.h>
 11 
 12 #define QLEN       5
 13 #define    WSVERS    MAKEWORD(2, 0)
 14 #define    BUFLEN    2000             // 缓冲区大小
 15 #pragma comment(lib,"ws2_32.lib")  //winsock 2.2 library
 16 
 17     SOCKET    msock, ssock;            /* master & slave sockets           */
 18     SOCKET    sockets[100] = {NULL};
 19      
 20      int cc;
 21      char    *pts;                    /* pointer to time string           */
 22      time_t    now;                    /* current time                       */
 23      char buf[2000];                      /* buffer                          */
 24      char *input;
 25      HANDLE hThread1,hThread[100] = {NULL};
 26     unsigned int threadID,ThreadID[100],number;
 27 
 28     struct    sockaddr_in fsin;
 29     struct    sockaddr_in Sin;
 30 
 31 unsigned int __stdcall Chat(PVOID PM) 
 32 {    
 33         char buf1[2000];
 34         char buf2[2000];
 35         char buf3[2000];
 36         char buf4[2000];
 37         (void) time(&now);
 38         pts = ctime(&now);
 39         sockets[number] = ssock;
 40         SOCKET    sock = ssock;
 41         ThreadID[number] = threadID;
 42         unsigned int threadid = threadID;
 43         sprintf(buf1," 时间: %s  \t【我的线程号: %d 】\n",pts,threadid);
 44         (void) send(sock,buf1, sizeof(buf1), 0); 
 45         sprintf(buf2," 线程号 <%d> 客户<IP:%s 端口:%d>  enter  \n",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port);
 46         printf("%s ",buf2);        
 47         printf("\t将自动把此数据发送给所有客户! \n");
 48         for(int i=0;i<=number;i++)
 49         {            
 50             if(sockets[i] != NULL && sockets[i] != sock)
 51             {
 52             (void) send(sockets[i],buf2, sizeof(buf2), 0); 
 53             printf(" 发送至线程号<%d>成功!\n",ThreadID[i]);
 54             }
 55         }
 56         printf(" \n");
 57 
 58 
 59 flag1:cc = recv(sock, buf3, BUFLEN, 0);   //cc为接收的字符数
 60     if(cc == SOCKET_ERROR|| cc == 0)
 61     {
 62         (void) time(&now);
 63         pts = ctime(&now);
 64         sprintf( buf3," 线程号 <%d> 客户<IP:%s 端口:%d>  leave !  \n \t\t时间: %s",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port,pts);
 65         sock = NULL;    
 66         sockets[number] = NULL;
 67         CloseHandle(hThread[number]);
 68         printf("%s ", buf3);        
 69         printf("\t将自动把此数据发送给所有客户! \n");
 70         for(int i=0;i<=number;i++)
 71         {            
 72             if(sockets[i] != NULL && sockets[i] != sock)
 73             {
 74             (void) send(sockets[i], buf3, sizeof(buf3), 0);     
 75             printf(" 发送至线程号<%d>成功!\n",ThreadID[i]);
 76             }            
 77         }
 78     printf(" \n");
 79     }
 80 
 81     else if(cc > 0) 
 82     {
 83         (void) time(&now);
 84         pts = ctime(&now);
 85     sprintf(buf4," 线程号 <%d> 客户<IP:%s 端口:%d>说 :%s  \n \t\t时间 : %s",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port,buf3,pts);
 86     
 87         printf("%s ",buf4);
 88         printf("\t将自动把此数据发送给所有客户! \n");
 89         for(int i=0;i<=number;i++)
 90         {            
 91             if(sockets[i] != NULL && sockets[i] != sock)
 92             {
 93             (void) send(sockets[i],buf4, sizeof(buf4), 0);         
 94             printf(" 发送至线程号<%d>成功!\n",ThreadID[i]);
 95             }            
 96         }
 97         printf(" \n");
 98 
 99         goto flag1;
100     }
101         (void) closesocket(sock);
102     
103         return 0;
104         }
105 
106 
107 /*------------------------------------------------------------------------
108  * main - Iterative TCP server for DAYTIME service
109  *------------------------------------------------------------------------
110  */
111 void main(int argc, char *argv[]) 
112 /* argc: 命令行参数个数, 例如:C:\> TCPdaytimed 8080 
113                      argc=2 argv[0]="TCPdaytimed",argv[1]="8080" */
114 {
115     int     alen;                    /* from-address length               */    
116     WSADATA wsadata; 
117     char    *service = "5050";    
118     WSAStartup(WSVERS, &wsadata);                         //加载 winsock 2.2 library
119     msock = socket(PF_INET, SOCK_STREAM, 0);              //生成套接字。TCP协议号=6, UDP协议号=17
120     memset(&Sin, 0, sizeof(Sin));
121     Sin.sin_family = AF_INET;
122     Sin.sin_addr.s_addr = INADDR_ANY;                    //指定绑定接口的IP地址。INADDR_ANY表示绑定(监听)所有的接口。
123     Sin.sin_port = htons((u_short)atoi(service));        //atoi--把ascii转化为int,htons - 主机序(host)转化为网络序(network), s(short) 
124     bind(msock, (struct sockaddr *)&Sin, sizeof(Sin));   // 绑定端口号(和IP地址)
125     listen(msock, 5);                                    //队列长度为5
126 
127     printf("\t\t\t\t Chat 多人聊天程序 \n");
128     printf("\t\t\t\t       (Server) \n");
129      (void) time(&now);
130       pts = ctime(&now);
131     printf("\t\t\t  时间 :%s",pts);
132         number = -1;
133     while(1)                                    //检测是否有按键
134     {                
135         alen = sizeof(struct sockaddr);
136         ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
137         number ++;
138         hThread[number] = (HANDLE)_beginthreadex(NULL, 0,Chat,NULL, 0, &threadID);        
139     }
140     (void) closesocket(msock);
141     WSACleanup();                         //卸载载 winsock 2.2 library
142 }

Client 部分:

  1 /* TCPClient.cpp  -- 用于传递struct */
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 #include <winsock2.h>
  5 #include <string.h>
  6 #include <time.h>
  7 #include <windows.h>
  8 #include <process.h>
  9 #include <math.h>
 10 
 11 #define    BUFLEN        2000                  // 缓冲区大小
 12 #define WSVERS        MAKEWORD(2, 0)        // 指明版本2.0 
 13 #pragma comment(lib,"ws2_32.lib")         // 指明winsock 2.0 Llibrary
 14 
 15 /*------------------------------------------------------------------------
 16  * main - TCP client for DAYTIME service
 17  *------------------------------------------------------------------------
 18  */
 19     
 20     SOCKET    sock,sockets[100] = {NULL};                          /* socket descriptor            */
 21 //    int    cc;                                /* recv character count            */
 22     char    *packet = NULL;               /* buffer for one line of text    */
 23     char *pts,*input;
 24     HANDLE hThread;
 25     unsigned threadID;
 26 
 27 unsigned int __stdcall Chat(PVOID PM ) 
 28 {
 29        time_t    now;
 30       (void) time(&now);
 31        pts = ctime(&now);
 32        char buf[2000];
 33 
 34 while(1)
 35 {
 36     int cc = recv(sock, buf, BUFLEN, 0);   //cc为接收的字符数
 37     if(cc == SOCKET_ERROR|| cc == 0)
 38     {
 39         printf("Error: %d.----",GetLastError());
 40         printf("与服务器断开连接!\n");
 41         CloseHandle(hThread);
 42         (void)closesocket(sock);
 43         break;
 44     }
 45     else if(cc > 0) 
 46     {
 47     //    buf[cc] = '\0';
 48         printf("%s\n",buf);
 49     //    printf("输入数据(exit退出):  \n");
 50     }     
 51 }
 52     return 0;
 53 }
 54 
 55 int main(int argc, char *argv[])
 56 {
 57     time_t    now;
 58      (void) time(&now);
 59        pts = ctime(&now);
 60     char    *host = "127.0.0.1";        /* server IP to connect         */
 61 //    char    *host = "172.18.33.155";
 62 //    char    *host = "172.18.33.93";
 63 //    char    *host = "172.18.187.1";
 64     char *service = "5050";          /* server port to connect       */
 65 //    char *service = "50000";
 66     struct  sockaddr_in sin;            /* an Internet endpoint address    */
 67     WSADATA wsadata;
 68     WSAStartup(WSVERS, &wsadata);       /* 启动某版本Socket的DLL        */        
 69 
 70     memset(&sin, 0, sizeof(sin));
 71     sin.sin_family = AF_INET;
 72     sin.sin_port = htons((u_short)atoi(service));    //atoi:把ascii转化为int. htons:主机序(host)转化为网络序(network), s--short
 73     sin.sin_addr.s_addr = inet_addr(host);           //如果host为域名,需要先用函数gethostbyname把域名转化为IP地址
 74 
 75     sock = socket(PF_INET, SOCK_STREAM,0);
 76 
 77     connect(sock, (struct sockaddr *)&sin, sizeof(sin));
 78 
 79     printf("\t\t\t\tChat 多人聊天程序 \n");
 80     printf("\t\t\t\t       (Client) \n");
 81     hThread = (HANDLE)_beginthreadex(NULL, 0,Chat, NULL, 0, &threadID);    
 82     printf(" \t\t\t\t 【您可以自由发言】\n\n");
 83 while(1)
 84 {
 85     char buf1[2000];
 86     
 87     //     scanf("%s",&buf1);
 88     
 89          gets_s(buf1);
 90          if(!strcmp(buf1 ,"exit"))
 91              goto end;
 92 
 93         (void) send(sock,buf1, sizeof(buf1), 0);
 94         (void) time(&now);
 95         pts = ctime(&now);
 96        printf(" 发送成功! ------时间: %s\n",pts);
 97 }
 98     
 99 end:    CloseHandle(hThread);
100         closesocket(sock);
101         WSACleanup();                     /* 卸载某版本的DLL */  
102 
103     printf("按回车键继续...");
104     getchar();
105     return 0;                           /* exit */
106 }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • wp15-1-24

    * 所有Task都有Show方法,调用Show方法启动任务,任务执行完毕一般会返回应用。所有任务都不是自动启动,而是需要用户手动点击启动

  • ZooKeeper分布式锁应用

    Zookeeper是一个高性能的分布式系统的协调服务。它在一个简单的接口里暴露公共服务:像命名、配置管理、同步、和群组服务,所以你没有必要从头开始实现它们。你可...

    会跳舞的机器人
  • 实现 | 朴素贝叶斯模型算法研究与实例分析

    构建一个快速过滤器来屏蔽在线社区留言板上的侮辱性言论。如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标识为内容不当。对此问题建立两个类别: 侮辱类和非侮...

    伏草惟存
  • 在PHP中使用MySQL Mysqli操作数据库 ,以及类操作方法

    先来操作函数部分,普遍的MySQL 函数方法,但随着PHP5的发展,有些函数使用的要求加重了,有些则将废弃不用,有些则参数必填...

    书童小二
  • 理论 | 朴素贝叶斯模型算法研究与实例分析

    朴素贝叶斯是一种构建分类器的简单方法。该分类器模型会给问题实例分配用特征值表示的类标签,类标签取自有限集合。所有朴素贝叶斯分类器都假定样本每个特征与其他特征都不...

    伏草惟存
  • 深度 | 朴素贝叶斯模型算法研究与实例分析

    本节介绍朴素贝叶斯分类算法模型在中文领域中的应用。我们对新闻语料进行多文本分类操作,本文选择艺术、文学、教育、哲学、历史五个类别的训练文本,然后采用新的测试语料...

    伏草惟存
  • 解开BIO、NIO、AIO神秘的面纱

    本文内容涉及同步与异步, 阻塞与非阻塞, BIO、NIO、AIO等概念, 这块内容本身比较复杂, 很难用三言两语说明白. 而书上的定义更不容易理解是什么意思. ...

    yukong
  • html5学习笔记(二)

    1. min、max、step属性用于包含数字或日期的input类型规定限定(约束)。

  • kubernetes源码阅读笔记:理清 kube-apiserver 的源码主线

    我最近开始研究 kubernetes 源码,希望将阅读笔记记录下来,分享阅读思路和心得,更好的理解 kubernetes,这是第一篇,从 kube-apiser...

    imroc
  • 针对Android中类的重载方法很多时的几种优化解决方案

    这个问题很多人在维护项目的时候可能会经常遇到,比如需求变更,刚开始只有一个构造方法,传入一个参数的。如下所示:

    AWeiLoveAndroid

扫码关注云+社区

领取腾讯云代金券