程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++ Socket 一個服務器 多個客戶端 (阻塞式)

C++ Socket 一個服務器 多個客戶端 (阻塞式)

編輯:關於C++

服務端
ServerNet.h

#pragma once
#include 
#include 
#include
#include
#include
#include 
#include
#include
using namespace std;

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


SOCKET sockConn;
HANDLE bufferMutex;     // 令其能互斥成功正常通信的信號量句柄  
vector clientSocketGroup; 
DWORD WINAPI WaitAcceptThread(LPVOID IpParameter);
DWORD WINAPI RecMsgThread(LPVOID IpParameter);
DWORD WINAPI SendMsgThread(LPVOID IpParameter);
map m_ipSocket;
class CServerNet
{
private:
    SOCKET m_sock;

public:
    CServerNet(void);
    //初始化服務器,返回0表示成功
    int Init(const char* address,int port);

    //更新數據
    void Run();



    ~CServerNet(void);

};

ServerNet.cpp

#include "ServerNet.h"

int CServerNet::Init( const char* address,int port )
{
    int rlt = 0;

    //用於記錄錯誤信息,並輸出
    int iErrorMsg;

    //初始化WinSock
    WSAData wsaData;
    iErrorMsg = WSAStartup(MAKEWORD(1,1),&wsaData);

    if (iErrorMsg != NO_ERROR)
    {
        //初始化WinSock失敗
        printf("wsastartup failed with error : %d\n",iErrorMsg);
        //WSAGetLastError()
        rlt = 1;
        return rlt;
    }

    //創建服務端Socket
    m_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (m_sock == INVALID_SOCKET)
    {
        //創建Socket異常
        printf("socket failed with error : %d\n",WSAGetLastError());
        rlt = 2;
        return rlt;
    }

    //聲明信息
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = port;
    serverAddr.sin_addr.s_addr = inet_addr(address);

    //綁定
    iErrorMsg = bind(m_sock,(sockaddr*)&serverAddr,sizeof(serverAddr));
    if (iErrorMsg < 0)
    {
        //綁定失敗
        printf("bind failed with error : %d\n",iErrorMsg);
        rlt = 3;
        return rlt;
    }



    return rlt;
}

void CServerNet::Run()
{
    //公開連接
    listen(m_sock,20);


    int len = sizeof(sockaddr);
    bufferMutex = CreateSemaphore(NULL, 1, 1, NULL);
    //HANDLE sendThread = CreateThread(NULL,0,)
    HANDLE acceptThread = CreateThread(NULL, 0, WaitAcceptThread, (LPVOID)m_sock, 0, NULL);
    //do 
    //{
    //  //接收信息
    //  newSocket = accept(m_sock,(sockaddr*)&tcpAddr,&len);

    //  
    //  if (newSocket == INVALID_SOCKET)
    //  {
    //      //非可用socket

    //  }
    //  else
    //  {
    //      //新socket連接
    //      printf("new socket connect : %d\n",newSocket);


    //      //消息處理
    //      do
    //      {
    //          printf("process\n");
    //          //接收數據
    //          memset(buf,0,sizeof(buf));
    //          rval = recv(newSocket,buf,1024,0);

    //          
    //          if (rval == SOCKET_ERROR)
    //          {
    //              //這應該是個異常,當客戶端沒有調用closeSocket就直接退出游戲的時候,將會進入這裡
    //              printf("recv socket error\n");
    //              break;
    //          }

    //          
    //          
    //          if (rval == 0)
    //              //recv返回0表示正常退出
    //              printf("ending connection");
    //          else
    //              //顯示接收到的數據
    //              printf("recv %s\n",buf);


    //      }while(rval != 0);

    //      //關閉對應Accept的socket
    //      closesocket(newSocket);
    //  }
    //  

    //  
    //} while (1);

    //關閉自身的Socket
    WaitForSingleObject(acceptThread, INFINITE);  // 等待線程結束 
    //WaitForSingleObject(sendThread, INFINITE);  // 等待線程結束  
    //CloseHandle(sendThread);  
    CloseHandle(bufferMutex);  
    WSACleanup();   // 終止對套接字庫的使用 
    closesocket(m_sock);
}





CServerNet::CServerNet(void)
{
}


CServerNet::~CServerNet(void)
{
}

DWORD WINAPI WaitAcceptThread(LPVOID IpParameter)
{
    SOCKET m_socket = (SOCKET)IpParameter;
    while(true)
    {
        sockaddr_in tcpAddr;
        int len = sizeof(sockaddr_in);
        sockConn = accept(m_socket, (sockaddr*)&tcpAddr, &len);
        char t[20];

        printf("%s:%d上線",inet_ntoa(tcpAddr.sin_addr),tcpAddr.sin_port);
        sprintf(t,"%s:%d",inet_ntoa(tcpAddr.sin_addr),tcpAddr.sin_port);
        string t1=t;
        if (SOCKET_ERROR != sockConn)
        {  
              clientSocketGroup.push_back(sockConn);  
              m_ipSocket[sockConn] = t1;
        } 
        HANDLE receiveThread = CreateThread(NULL, 0, RecMsgThread, (LPVOID)sockConn, 0, NULL);
        WaitForSingleObject(bufferMutex, INFINITE);     // P(資源未被占用)   
         if(NULL == receiveThread) {   
            printf("\nCreatThread AnswerThread() failed.\n");   
        }   
        else{   
           printf("\nCreate Receive Client Thread OK.\n");   
       }   
       ReleaseSemaphore(bufferMutex, 1, NULL);
    }
}

DWORD WINAPI RecMsgThread(LPVOID IpParameter)
{
    SOCKET ClientSocket=(SOCKET)(LPVOID)IpParameter;
    int rval;
    while(1)
    {
        char recvBuf[1024];  
        rval = recv(ClientSocket, recvBuf, 1024, 0);  
        WaitForSingleObject(bufferMutex, INFINITE);
        if (rval == SOCKET_ERROR)
        {
            printf("ONE Client Exit\n");
            vector::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket);  
            clientSocketGroup.erase(result);  
            for (map::iterator i=m_ipSocket.begin(); i!=m_ipSocket.end(); i++)  
            {  
                if (i->first == ClientSocket)  
                {  
                    printf("%s下線\n",m_ipSocket[ClientSocket].c_str());
                    m_ipSocket.erase(i);
                    break;
                }  
            }  
            closesocket(ClientSocket);  
            ReleaseSemaphore(bufferMutex, 1, NULL);
            break;
        }
        printf("%s Says: %s\n", m_ipSocket[ClientSocket].c_str(), recvBuf);     // 接收信息
        ReleaseSemaphore(bufferMutex, 1, NULL);
    }
    return 0;
}

int main()
{
    CServerNet serverNet;
    int iRlt = serverNet.Init("127.0.0.1",8888);
    if (iRlt == 0)
    {
        printf("init ok...\n");
        serverNet.Run();
    }
    else
        printf("serverNet init failed with error : %d\n",iRlt);
    system("pause");
    return 0;
}

客戶端
ClientNet.h

#pragma once
#include
#include
#pragma comment(lib, "Ws2_32.lib")
class CClientNet
{
private:
    SOCKET m_sock;
public:
    CClientNet(void);
    //連接上指定服務器
    int Connect(int port,const char* address);
    //發送信息
    int SendMsg(const char* msg,int len);
    //關閉
    void Close();
    ~CClientNet(void);
};

ServerNet.cpp

#include "ServerNet.h"

int CServerNet::Init( const char* address,int port )
{
    int rlt = 0;

    //用於記錄錯誤信息,並輸出
    int iErrorMsg;

    //初始化WinSock
    WSAData wsaData;
    iErrorMsg = WSAStartup(MAKEWORD(1,1),&wsaData);

    if (iErrorMsg != NO_ERROR)
    {
        //初始化WinSock失敗
        printf("wsastartup failed with error : %d\n",iErrorMsg);
        //WSAGetLastError()
        rlt = 1;
        return rlt;
    }

    //創建服務端Socket
    m_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (m_sock == INVALID_SOCKET)
    {
        //創建Socket異常
        printf("socket failed with error : %d\n",WSAGetLastError());
        rlt = 2;
        return rlt;
    }

    //聲明信息
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = port;
    serverAddr.sin_addr.s_addr = inet_addr(address);

    //綁定
    iErrorMsg = bind(m_sock,(sockaddr*)&serverAddr,sizeof(serverAddr));
    if (iErrorMsg < 0)
    {
        //綁定失敗
        printf("bind failed with error : %d\n",iErrorMsg);
        rlt = 3;
        return rlt;
    }



    return rlt;
}

void CServerNet::Run()
{
    //公開連接
    listen(m_sock,20);


    int len = sizeof(sockaddr);
    bufferMutex = CreateSemaphore(NULL, 1, 1, NULL);
    //HANDLE sendThread = CreateThread(NULL,0,)
    HANDLE acceptThread = CreateThread(NULL, 0, WaitAcceptThread, (LPVOID)m_sock, 0, NULL);
    //do 
    //{
    //  //接收信息
    //  newSocket = accept(m_sock,(sockaddr*)&tcpAddr,&len);

    //  
    //  if (newSocket == INVALID_SOCKET)
    //  {
    //      //非可用socket

    //  }
    //  else
    //  {
    //      //新socket連接
    //      printf("new socket connect : %d\n",newSocket);


    //      //消息處理
    //      do
    //      {
    //          printf("process\n");
    //          //接收數據
    //          memset(buf,0,sizeof(buf));
    //          rval = recv(newSocket,buf,1024,0);

    //          
    //          if (rval == SOCKET_ERROR)
    //          {
    //              //這應該是個異常,當客戶端沒有調用closeSocket就直接退出游戲的時候,將會進入這裡
    //              printf("recv socket error\n");
    //              break;
    //          }

    //          
    //          
    //          if (rval == 0)
    //              //recv返回0表示正常退出
    //              printf("ending connection");
    //          else
    //              //顯示接收到的數據
    //              printf("recv %s\n",buf);


    //      }while(rval != 0);

    //      //關閉對應Accept的socket
    //      closesocket(newSocket);
    //  }
    //  

    //  
    //} while (1);

    //關閉自身的Socket
    WaitForSingleObject(acceptThread, INFINITE);  // 等待線程結束 
    //WaitForSingleObject(sendThread, INFINITE);  // 等待線程結束  
    //CloseHandle(sendThread);  
    CloseHandle(bufferMutex);  
    WSACleanup();   // 終止對套接字庫的使用 
    closesocket(m_sock);
}





CServerNet::CServerNet(void)
{
}


CServerNet::~CServerNet(void)
{
}

DWORD WINAPI WaitAcceptThread(LPVOID IpParameter)
{
    SOCKET m_socket = (SOCKET)IpParameter;
    while(true)
    {
        sockaddr_in tcpAddr;
        int len = sizeof(sockaddr_in);
        sockConn = accept(m_socket, (sockaddr*)&tcpAddr, &len);
        char t[20];

        printf("%s:%d上線",inet_ntoa(tcpAddr.sin_addr),tcpAddr.sin_port);
        sprintf(t,"%s:%d",inet_ntoa(tcpAddr.sin_addr),tcpAddr.sin_port);
        string t1=t;
        if (SOCKET_ERROR != sockConn)
        {  
              clientSocketGroup.push_back(sockConn);  
              m_ipSocket[sockConn] = t1;
        } 
        HANDLE receiveThread = CreateThread(NULL, 0, RecMsgThread, (LPVOID)sockConn, 0, NULL);
        WaitForSingleObject(bufferMutex, INFINITE);     // P(資源未被占用)   
         if(NULL == receiveThread) {   
            printf("\nCreatThread AnswerThread() failed.\n");   
        }   
        else{   
           printf("\nCreate Receive Client Thread OK.\n");   
       }   
       ReleaseSemaphore(bufferMutex, 1, NULL);
    }
}

DWORD WINAPI RecMsgThread(LPVOID IpParameter)
{
    SOCKET ClientSocket=(SOCKET)(LPVOID)IpParameter;
    int rval;
    while(1)
    {
        char recvBuf[1024];  
        rval = recv(ClientSocket, recvBuf, 1024, 0);  
        WaitForSingleObject(bufferMutex, INFINITE);
        if (rval == SOCKET_ERROR)
        {
            printf("ONE Client Exit\n");
            vector::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket);  
            clientSocketGroup.erase(result);  
            for (map::iterator i=m_ipSocket.begin(); i!=m_ipSocket.end(); i++)  
            {  
                if (i->first == ClientSocket)  
                {  
                    printf("%s下線\n",m_ipSocket[ClientSocket].c_str());
                    m_ipSocket.erase(i);
                    break;
                }  
            }  
            closesocket(ClientSocket);  
            ReleaseSemaphore(bufferMutex, 1, NULL);
            break;
        }
        printf("%s Says: %s\n", m_ipSocket[ClientSocket].c_str(), recvBuf);     // 接收信息
        ReleaseSemaphore(bufferMutex, 1, NULL);
    }
    return 0;
}

int main()
{
    CServerNet serverNet;
    int iRlt = serverNet.Init("127.0.0.1",8888);
    if (iRlt == 0)
    {
        printf("init ok...\n");
        serverNet.Run();
    }
    else
        printf("serverNet init failed with error : %d\n",iRlt);
    system("pause");
    return 0;
}
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved