Windows Socket 编程 : 支持多线程(TCP)(环境:VS2010)

本文介绍了一个基于TCP协议的简单聊天室系统的实现过程,包括客户端和服务端的代码设计与功能实现。该系统支持用户登录、发送消息给指定用户或全体用户、获取在线用户列表等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. UserMesInfo.h 公共文件,客户端和服务器端公用;

#ifndef  User_Mes_Sock
#define  User_Mes_Sock
#include <winsock2.h>
#endif

const short  MesLogin   =  1001;
const short  MesError   =  1002;
const short  MesNormal  =  1003;
const short  LoginSuc   =  1004;
const short  MesToAll   =  1005;
const short  OnLineUser =  1010;


//User Struct
struct UserInfo
{
    short        userId;
    char         userName[32];
    SOCKET       userSock;
    LONG         userAddr;
    UserInfo     *pNext;
};

//Message Struct
struct MesInfo
{
    short        MesType;
    char         fromUserName[32];
    char         toUserName[32];
    char         MesContent[1024];
};

 

2. TCP:客户端程序

 

#include <iostream>
#include <stdlib.h>
#include <WinSock2.h>

#include "UserMesInfo.h"

#pragma comment(lib,"ws2_32.lib")

using namespace std;

BOOL isLogin = false;


string charToString(char temp[])
{
    string tempStr = "";
    for(int i = 0; i < sizeof(temp); i++)
        tempStr += temp[i];
    return tempStr;
}

BOOL SendMes(SOCKET servSocket)
{
    SOCKET servSock = servSocket;
    while(TRUE)
    {
        int tempWho;
        char sendBuff[1024] = {0};
        if(isLogin)
        {
            printf(" '1' : speak to ONE ;\n '2' : speak to ALL ;\n '3' : OnLine Users ; \n '4' : Exit ;\n");

            cin>>tempWho;
        }
        if( isLogin && tempWho == 1)
        {
            //To One
            printf("Please input NAME you want to CHAT : ");
            char toName[32] = {0};
            scanf("%s", toName);
            memcpy(sendBuff, &MesNormal, 2);
            memcpy(sendBuff+2, toName, 32);
            printf("Please input what do you want to say : ");
            char Message[1000] = {0};
            scanf("%s", Message);
            memcpy(sendBuff+34, Message, strlen(Message));
            send(servSock, sendBuff, sizeof(sendBuff)+1, 0);
        } else if(isLogin && tempWho == 2){
            //To ALL
            printf("Please input DATA : ");
            char Message[1000] = {0};
            scanf("%s", Message);

            memcpy(sendBuff, &MesToAll, 2);
            memcpy(sendBuff+2, Message, strlen(Message));
            send(servSock, sendBuff, sizeof(sendBuff)+1, 0);

        } else if(isLogin && tempWho == 3){
            char getOnLineUsers[4];
            memcpy(getOnLineUsers, &OnLineUser, 2);
            send(servSock, getOnLineUsers, sizeof(getOnLineUsers), 0);
        } else if(isLogin && tempWho == 4){
            break;
        } else if(isLogin){
            printf("You input Error! Please Again !");
        }
       
    }
    return TRUE;
}


DWORD WINAPI ProcThread(LPVOID lpParameter)
{
    SOCKET cliSocket = *(SOCKET*)lpParameter;

    //SOCKADDR_IN sockFrom ;
    //int length = sizeof(SOCKADDR);

    char recvBuf[1024] = {0};

    while(true)
    {
        memset(recvBuf, 0x00, 1024);
        int recvLen = recv(cliSocket, recvBuf, 1024, 0);
        if(recvLen > 0)
        {
            short megId = *(short*)recvBuf;
            switch(megId)
            {
            case LoginSuc:
                {
                    //char userName[32] = {0};
                    //memcpy(userName, recvBuf+2, 4);
                    printf("Login Success !\n");
                    isLogin = true;
                }
                break;
            case MesNormal:
                {
                    char Mess[1000];
                    memcpy(Mess, recvBuf+2, sizeof(recvBuf)-2);
                    printf(" ==> Me :%s\n", Mess);
                   
                }
                break;
            case MesToAll:
                {
                    char Mess[1000];
                    memcpy(Mess, recvBuf+2, sizeof(recvBuf)-2);
                    printf(" ==> All :%s\n", Mess);
                }
                break;
            case OnLineUser:
                {
                    char onLineUser[100] = {0};
                   
                    memcpy(onLineUser, recvBuf+2, sizeof(recvBuf)-2);

                    //string userStr = charToString(onLineUser);
                   
                    for(int i =0; i < sizeof(onLineUser); i++)
                        cout<<onLineUser[i];

                    //printf("%s\n", userStr);
                    cout<<endl<<onLineUser<<endl;
                    printf("\n");
           
                }
                break;
            default :
                break;
            }
        }//end if
    }// end while

    return 0;
}

int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


    SOCKET clientSock = socket(AF_INET, SOCK_STREAM, 0);

    if(clientSock == -1)
    {
        perror("socket创建出错!");
        exit(1);
    }

    SOCKADDR_IN addrClient;
    addrClient.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addrClient.sin_family = AF_INET;
    addrClient.sin_port = htons(6000);


    int ret = connect(clientSock, (sockaddr*)&addrClient, sizeof(SOCKADDR));
    if (ret)
    {
        printf("连接失败\n");
        return -1;
    }

    HANDLE thHandle = CreateThread(NULL, 0, ProcThread, &clientSock, 0, NULL);

    if(NULL == thHandle)
    {
        cout<<"Create Thread failed !"<<endl;
        return -1;
    }

    char userName[32];
    printf("Please input name : ");
    scanf_s("%s", userName, 31);

    /*
    UserInfo* user = new UserInfo;
    user->userSock = clientSock;
    strcpy_s(user->userName, userName);
    user->userAddr = addrClient.sin_addr.S_un.S_addr;
    */
   
    char loginInfo[64] = {0};
    memcpy(loginInfo, &MesLogin, 2);
    memcpy(loginInfo+2, userName, strlen(userName));

   
    //int a = send(clientSock, loginInfo, strlen(loginInfo), 0);
    int a = send(clientSock, loginInfo, strlen(loginInfo), 0);
   
    SendMes(clientSock);

    //Sleep(20000);
    //closesocket(clientSock);
    CloseHandle(thHandle);
    WSACleanup();

   
    system("PAUSE");
    return 0;
}

 3.TCP:服务器端程序

 

#include <iostream>
#include <cstdlib>
#include <winsock2.h>
#include <string>
#include <Windows.h>
#include "UserMesInfo.h"

#pragma comment(lib,"ws2_32.lib")

using namespace std;

UserInfo *gUserInfo ;

string charToString(char temp[])
{
    string tempStr = "";
    for(int i = 0; i < sizeof(temp); i++)
        tempStr += temp[i];
    return tempStr;
}


DWORD WINAPI ProcMes(LPVOID lpParameter)
{
    SOCKET cliSocket = ((UserInfo*)lpParameter)->userSock;
    //SOCKADDR_IN sockFrom ;

    char recvBuf[1024];
    //int length = sizeof(SOCKADDR);

    while(true)
    {
        memset(recvBuf, 0x00, 1024);
        recv(cliSocket, recvBuf, 1024, 0);
       
        short MesType = *(short*)recvBuf;

        switch(MesType)
        {
        case MesLogin:
            {
                static short USERID = 1001;
                UserInfo* userInfo = new UserInfo;
                char* userName = (char*)(recvBuf + 2);
                strcpy_s(userInfo->userName, userName);
                userInfo->userId = USERID++;
                userInfo->userSock = cliSocket;
                userInfo->userAddr = ((UserInfo*)lpParameter)->userAddr;
                userInfo->pNext = NULL;

                if(!gUserInfo)
                {
                    gUserInfo = userInfo;
                }else
                {
                    userInfo->pNext = gUserInfo;
                    gUserInfo = userInfo;
                }
                printf("Login  :  %s ==> %d !\n", userInfo->userName, userInfo->userId);
               
                char loginInfo[4] = {0};
                memcpy(loginInfo, &LoginSuc, 2);
               
                int i = send(cliSocket, loginInfo, strlen(loginInfo), 0);
               
            }
            break;
        case MesNormal:
            {
                //printf("The Normal Message !");
                char toName[32] = {0};
                memcpy(toName, recvBuf+2, 32);
                cout<<toName<<endl;
                char Message[1000] = {0};
                memcpy(Message, recvBuf+34, sizeof(recvBuf)-34);
                printf("%s\n", Message);

                char sendMes[1006];
                memcpy(sendMes, &MesNormal, 2);
                memcpy(sendMes+2, recvBuf+34, sizeof(recvBuf)-34);
               
                //send(toSock, sendMes, sizeof(sendMes), 0);

                UserInfo* tempUser = gUserInfo;
                BOOL sendFlag = false;
                while(tempUser)
                {
                    if(!memcmp(toName, tempUser->userName, strlen(toName)))
                    {
                        SOCKET toSock = tempUser->userSock;
                        send(toSock, sendMes, strlen(sendMes)+1, 0);
                        sendFlag = true;
                    }
                    tempUser = tempUser->pNext;
                }
                if(!sendFlag)
                {
                    printf("Send Failed !\n");
                }
               
            }
            break;
        case MesToAll:
            {
                char Message[1000] = {0};
                memcpy(Message, recvBuf+2, sizeof(recvBuf)-2);
                UserInfo* tempUser = gUserInfo;
                char sendMes[1002];
                memcpy(sendMes, &MesToAll, 2);
                memcpy(sendMes+2, Message, sizeof(Message));
                while(tempUser)
                {
                    SOCKET toSock = tempUser->userSock;
                    int i = send(toSock, sendMes, strlen(sendMes)+1, 0);
                    if(i > 0)
                    {
                        printf("Send To %s Success !\n", tempUser->userName);
                    }
                    tempUser = tempUser->pNext;
                }
            }
            break;
        case MesError:
            //printf("The Error Message !");
            break;
        case OnLineUser:
            {
               
                char onLineUserBuff[1000] = {0};
                UserInfo* tempUser = gUserInfo;
               
                memcpy(onLineUserBuff, &OnLineUser, 2);

                int i = 0;
                string userStr = "";
                while(tempUser)
                {
                    userStr += charToString(tempUser->userName);
                    //处理方式有问题
                    //memcpy(onLineUserBuff+2, tempUser->userName, 32);
                    //send(cliSocket, onLineUserBuff, sizeof(onLineUserBuff), 0);
                    tempUser = tempUser->pNext;
                }
                memcpy(onLineUserBuff+2, userStr.c_str(), userStr.length());
                send(cliSocket, onLineUserBuff, sizeof(onLineUserBuff), 0);
                       
            }
            break;
        default:
            //printf("The Default Process !");
            break;
        }
   
    }

   
    return 0;
}

int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(2, 2);

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        printf("WSAStartup failed with error: %d\n", err);
        return 1;
    }

    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("Could not find a usable version of Winsock.dll\n");
        WSACleanup();
        return 1;
    }
    else
        printf("The Winsock 2.2 dll was found okay\n");


    SOCKET servSock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN addrServ ;
    addrServ.sin_family = AF_INET;
    addrServ.sin_port = htons(6000);
    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

    bind(servSock, (SOCKADDR*)&addrServ, sizeof(SOCKADDR));

    if(listen(servSock, 20) == SOCKET_ERROR)
    {
        printf("listen failed with error: %ld\n", WSAGetLastError());
        closesocket(servSock);
        WSACleanup();
        return -1;
    }


    while(true)
    {
        //wait for users Login, and create thread for it
        SOCKADDR_IN cliAddr;
        int length = sizeof(SOCKADDR);

        SOCKET cliSock = accept(servSock, (SOCKADDR*)&cliAddr, &length);

        if(INVALID_SOCKET == cliSock)
        {
            printf("listen failed with error: %ld\n", WSAGetLastError());
            closesocket(cliSock);
            WSACleanup();
            return -1;
        }

        UserInfo* user = new UserInfo;

        user->userSock = cliSock;
        user->userAddr = cliAddr.sin_addr.S_un.S_addr;

        //cout<<sizeof(user->userName)<<endl;

        HANDLE loginHandle = CreateThread(NULL, 0, ProcMes, (LPVOID)user, 0, NULL);

        if(NULL == loginHandle)
        {
            cout<<"Create Thread failed !"<<endl;
            return -1;
        }
        CloseHandle(loginHandle);

    }
    //Sleep(20000);
    closesocket(servSock);
    WSACleanup();

    system("PAUSE");
    return 0;
}

 

转自http://www.cnblogs.com/china-victory/archive/2012/11/17/2775404.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值