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

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
网关程序:主要目的是作了一个中间程序转发网络消息,其实在网上有很多这样的程序,比如跨平台的ACE,目前版本为5.6,如果从ACE开始学习网关,个人觉得挺费劲的,我也曾经想用ACE编写网关程序,后来由于ACE的复杂性,还是胆怯了,还是自己下定决心写了一个网关程序。该网关程序目前只支持Windows,下一步的目标准备将程序移植到GCC环境下。程序中用到STL的std::map和std::list,也大量的运行了模板类,如:关于线程的参数ARGS即为模板类:template ARGS{}、还有一个就是SOCKET结构体:HOSTSTRUCTSTRCT的定义也是用到了模板类。程序的主要部份为:class CFramework 文件:framework.h framework.cpp,如果想编写一个网关程序,首先需要从该类继承,如目前例程中的:class CMyGateway;大家都知道网关程序即SOCKET通讯多线程程序,其中当然用到SOCKET;网关中有SOCKET服务端,也有SOCKET客户端;作为SOCKET服务端时,需要接收远程主机的连接,当远程主机请求连接,根据业务需要首先要验证该客户端是否是合法的客户,此时,需要从系统的允许访问队列表查询是否有该主机的信息,如果有该主机的信息,则允许该主机连接,此时触发OnConnected事件,在该事件中,可以接收客户端的登录信息,验证客户端的登录信息,如果验证成功,则将该主机信息添加到系统路由表中,当有消息需要转发到该主机时,从系统路由表取到目标主机的信息,通过host.fd发送消息;同理,网关作为一个客户端时,需要连接其它远程服务器,一旦连接上后,触发OnConnected事件,在该事件中,我们可以发送登录信息,并接收应答信息,解析应答信息,判断我们的登录是否成功,如果成功的话,将连接主机的信息添加到系统路由表中,当有其它信息需要转发到该主机时,从系统路由表中取到连接信息通过send() host.fd转发信息。在class CFramework中还有一定非常重要的函数:OnExecuteMessagte(const xuwn::MESSAGE& message)方法,这个方法是在从消息队列取到消息后执行的,xuwn::MESSAGE中定义了一个buffer即收到的消息,同时消息的长度为:message.size.nhead+message.size.nbody,您可以处理消息,在模拟程序中,我将消息转发到另外一个服务器即:B_HOST,HOSTSTRUCT的有个字段name即我称之为节点名称,该名称是我作为索引用的,在系统路由中只能存在这样一个KEY值的HOSTSTRUCT;在class CFramework中还有一个重要函数:OnRecvData(const HOSTSTRCT& host__, xuwn::MESSAGE& message),这个方法是由我们执行如何接收消息的,因为大多数时候我们定义消息都为变长,即消息存在消息头+消息体,大多时候,消息头为定长,消息体的长度在消息头中体现,当我们接收完消息头后,设置后继包(消息体)的长度,再调用CFramework::OnRecvData(host__, message)去接收消息体,并把消息写入到消息队列中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值