多线程实现客户端 服务器简单聊天

简要说明:在课设时在网上找了很久才找到一篇有所帮助的分享,本篇博客只是在原博客基础上进行了些许的修改,在此只做收藏之用!

源代码转自:https://www.cnblogs.com/imwtr/p/4072452.html

///服务器:

#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <time.h>
#include "conio.h"
#include <windows.h>
#include <process.h>
#include <math.h>
#define QLEN       5
#define    WSVERS    MAKEWORD(2, 0)
#define    BUFLEN    2000             // 缓冲区大小
#pragma comment(lib,"ws2_32.lib")  //winsock 2.2 library

SOCKET    msock, ssock;            /* master & slave sockets           */
SOCKET    sockets[100] = {NULL};

int cc;
char buf[2000];                      /* buffer                          */
char *input;
HANDLE hThread1,hThread[100] = {NULL};
unsigned int threadID,ThreadID[100],number;

struct    sockaddr_in fsin;
struct    sockaddr_in Sin;

unsigned int __stdcall Chat(PVOID PM)
{
    char buf1[2000];
    char buf2[2000];
    char buf3[2000];
    char buf4[2000];

    sockets[number] = ssock;
    SOCKET    sock = ssock;
    ThreadID[number] = threadID;
    unsigned int threadid = threadID;
    sprintf(buf1,"【我的线程号:%d】\n",threadid);//每创建一个客户端服务器会给该客户端随机分配一个线程号
    (void) send(sock,buf1, sizeof(buf1), 0);
    sprintf(buf2," 线程号 <%d> 客户<IP:%s 端口:%d>  加入了! \n",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port);
    printf("%s ",buf2);
    for(int i=0; i<=number; i++)
    {
        if(sockets[i] != NULL && sockets[i] != sock)
        {
            (void) send(sockets[i],buf2, sizeof(buf2), 0);
            printf(" 发送至线程号<%d>成功!\n",ThreadID[i]);
        }
    }
    printf(" \n");


flag1:
    cc = recv(sock, buf3, BUFLEN, 0);   //cc为接收的字符数
    if(cc == SOCKET_ERROR|| cc == 0)
    {

        sprintf( buf3," 线程号 <%d> 客户<IP:%s 端口:%d>  离开了!  \n",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port);
        sock = NULL;
        sockets[number] = NULL;
        CloseHandle(hThread[number]);
         printf("%s ", buf3);
        // printf("\t将自动把此数据发送给所有客户! \n");
        for(int i=0; i<=number; i++)
        {
            if(sockets[i] != NULL && sockets[i] != sock)
            {
                (void) send(sockets[i], buf3, sizeof(buf3), 0);
                printf(" 发送至线程号<%d>成功!\n",ThreadID[i]);
            }
        }
        printf(" \n");
    }

    else if(cc > 0)
    {
        sprintf(buf4," 线程号 <%d> 客户<IP:%s 端口:%d>说 :%s  \n ",threadid,inet_ntoa(fsin.sin_addr),fsin.sin_port,buf3);
        printf("%s ",buf4);
        //printf("将自动把此数据发送给所有客户! \n");
        for(int i=0; i<=number; i++)
        {
            if(sockets[i] != NULL && sockets[i] != sock)
            {
                (void) send(sockets[i],buf4, sizeof(buf4), 0);
                printf(" 转发至线程号<%d>成功!\n",ThreadID[i]);//将从A客户端收到的数据转发给A以外的每个客户端
            }
        }
        printf(" \n");
        goto flag1;
    }
    (void) closesocket(sock);
    return 0;
}
DWORD WINAPI sendFunction(LPVOID lpParameter)//添加一个线程用来实现服务器端给客户端发送数据
{
    char sendBuf[50];
    SOCKET sock = ssock;
    sockets[number] = ssock;
    while(1)
    {
        gets(sendBuf);//scanf("%s",sendBuf);
        for(int i=0; i<number; i++)
        {
            if(sockets[i] != NULL && sockets[i] != sock)
            {
                (void) send(sockets[i],sendBuf, sizeof(sendBuf), 0);
                printf(" 发送成功!\n");
            }
        }


    }
}
int main(int argc, char *argv[])
/* argc: 命令行参数个数, 例如:C:\> TCPdaytimed 8080
                     argc=2 argv[0]="TCPdaytimed",argv[1]="8080" */
{
    int     alen;                    /* from-address length               */
    WSADATA wsadata;
    char    *service = "5050";
    WSAStartup(WSVERS, &wsadata);                         //加载 winsock 2.2 library
    msock = socket(PF_INET, SOCK_STREAM, 0);              //生成套接字。TCP协议号=6, UDP协议号=17
    memset(&Sin, 0, sizeof(Sin));
    Sin.sin_family = AF_INET;
    Sin.sin_addr.s_addr = INADDR_ANY;                    //指定绑定接口的IP地址。INADDR_ANY表示绑定(监听)所有的接口。
    Sin.sin_port = htons((u_short)atoi(service));        //atoi--把ascii转化为int,htons - 主机序(host)转化为网络序(network), s(short)
    bind(msock, (struct sockaddr *)&Sin, sizeof(Sin));   // 绑定端口号(和IP地址)
    listen(msock, 5);                                    //队列长度为5

    printf("我是服务器!!!\n");
    number = -1;
    while(1)                                    //检测是否有按键
    {
        alen = sizeof(struct sockaddr);
        ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
        number ++;
        hThread1=(HANDLE)_beginthreadex(NULL,0,sendFunction,NULL,0,NULL);
        hThread[number] = (HANDLE)_beginthreadex(NULL, 0,Chat,NULL, 0, &threadID);
    }
    (void) closesocket(msock);
    WSACleanup();                         //卸载载 winsock 2.2 library
}

 

///客户端:

/* TCPClient.cpp  -- 用于传递struct */
#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <process.h>
#include <math.h>

#define    BUFLEN        2000                  // 缓冲区大小
#define WSVERS        MAKEWORD(2, 0)        // 指明版本2.0
#pragma comment(lib,"ws2_32.lib")         // 指明winsock 2.0 Llibrary
    SOCKET    sock,sockets[100] = {NULL};                          /* socket descriptor            */
//    int    cc;                                /* recv character count            */
    char    *packet = NULL;               /* buffer for one line of text    */
    char *pts,*input;
    HANDLE hThread;
    unsigned threadID;

unsigned int __stdcall Chat(PVOID PM )
{
       char recvbuf[2000];

while(1)
{
    int cc = recv(sock, recvbuf, BUFLEN, 0);   //cc为接收的字符数
    if(cc == SOCKET_ERROR|| cc == 0)
    {
        printf("Error: %d.----",GetLastError());
        printf("与服务器断开连接!\n");
        CloseHandle(hThread);
        (void)closesocket(sock);
        break;
    }
    else if(cc > 0)
    {
        printf("%s\n",recvbuf);
    }
}
    return 0;
}

int main(int argc, char *argv[])
{
    time_t    now;
     (void) time(&now);
       pts = ctime(&now);
    char    *host = "127.0.0.1";        /* server IP to connect         */
    char *service = "5050";          /* server port to connect       */
    struct  sockaddr_in sin;            /* an Internet endpoint address    */
    WSADATA wsadata;
    WSAStartup(WSVERS, &wsadata);       /* 启动某版本Socket的DLL        */

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons((u_short)atoi(service));    //atoi:把ascii转化为int. htons:主机序(host)转化为网络序(network), s--short
    sin.sin_addr.s_addr = inet_addr(host);           //如果host为域名,需要先用函数gethostbyname把域名转化为IP地址

    sock = socket(PF_INET, SOCK_STREAM,0);

    connect(sock, (struct sockaddr *)&sin, sizeof(sin));

    printf("我是客户端!!!");

    hThread = (HANDLE)_beginthreadex(NULL, 0,Chat, NULL, 0, &threadID);

while(1)
{
    char buf1[2000];

    //     scanf("%s",&buf1);

         gets(buf1);
         if(!strcmp(buf1 ,"exit"))
             goto end;

        (void) send(sock,buf1, sizeof(buf1), 0);
         printf(" 发送成功!\n");
}

end:    CloseHandle(hThread);
        closesocket(sock);
        WSACleanup();                     /* 卸载某版本的DLL */

    printf("按回车键继续...");
    getchar();
    return 0;                           /* exit */
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值