1. 程式人生 > >C++ Socket 一個伺服器 多個客戶端 (阻塞式)

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

服務端
ServerNet.h

#pragma once
#include <stdio.h>
#include <winsock.h>
#include<vector>
#include<iterator>
#include<iostream>
#include <algorithm>
#include<map>
#include<string>
using namespace std;

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


SOCKET sockConn;
HANDLE bufferMutex;     // 令其能互斥成功正常通訊的訊號量控制代碼  
vector<SOCKET> clientSocketGroup; DWORD WINAPI WaitAcceptThread(LPVOID IpParameter); DWORD WINAPI RecMsgThread(LPVOID IpParameter); DWORD WINAPI SendMsgThread(LPVOID IpParameter); map<SOCKET,string> 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<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket); clientSocketGroup.erase(result); for (map<SOCKET, string>::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<stdio.h>
#include<Windows.h>
#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<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket);  
            clientSocketGroup.erase(result);  
            for (map<SOCKET, string>::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;
}

相關推薦

C++ Socket 一個伺服器 客戶 阻塞

服務端 ServerNet.h #pragma once #include <stdio.h> #include <winsock.h> #include<vector> #include<iterator>

socket ( java ) 簡單客戶、服務通訊執行緒

實現: 客戶端:多個socket(多個埠),其中一個客戶端的一個埠用於接收服務端傳送過來的訊息,其一個用於向服務端傳送訊息。其它客戶端只有發訊息的功能。 服務端:兩個socket,一個用於迴圈接收客戶端傳送過來的socket請求。一個用於接收訊息手自動向客戶端

Unity中的Socket通訊客戶的非同步通訊

using UnityEngine; using System; using System.Net; using System.Net.Sockets; using System.Collections; using System.Text; using System.Collections.Generic;

Cloudera Manager安裝之時間伺服器和時間客戶Ubuntu14.04

   第二步:  找一臺機器作為時間伺服器   我這裡,放到ubuntucmbigdata1這臺機器!   注意,之前是已經做了叢集時間同步了。   在ubuntu系統裡,跟centos系統有點出入。   需要安裝 [email protected

C#一個伺服器客戶Socket通訊

原理: 啟動服務端後,服務端通過持續監聽客戶端發來的請求,一旦監聽到客戶端傳來的資訊後,兩端便可以互發資訊了。伺服器端需要繫結一個IP和埠號,用於客戶端在網路中尋找並建立連線。資訊傳送原理:將手動輸入字串資訊轉換成機器可以識別的位元組陣列,然後呼叫套接字的Send()方法將位元組陣列傳送出去

C++ Socket網路通訊實現一個伺服器客戶的通訊

一 描述1 採用C++語言 2 編譯環境是code::blocks 3 使用的是非阻塞套接字 二 功能描述1 一個伺服器對多個客戶端 2 伺服器端主要負責處理資料的輸入併發送,具體是通過傳送指令向其指定的客戶端傳送資料,傳送接收指令讀取其指定的客戶端傳送的資料 3 客戶端的

Socket通訊 一個伺服器客戶,不能延遲接受資訊的實現

實驗要求: 1.一個時間點,無論哪個基站有資料傳送,伺服器必須同時接收。不能延遲等待這個客戶端接收完畢再接收另一個客戶端; 2.客戶端不能關閉,一直連線,以防資料遺漏 知識點: 多執行緒 同時開啟多個任務,不用按照程式的執行順序來; 基本的程式碼如下: pack

基於非阻塞socket執行緒伺服器的實現------一個伺服器如何與客戶進行通訊?

      我們首先來看服務端(涉及非阻塞socket和多執行緒): #include <stdio.h> #include <winsock2.h> #include <windows.h> #pragma comment(li

socket實現客戶連線在一個伺服器

1、使用socekt通訊一般步驟     1)伺服器端:socker()建立套接字,繫結(bind)並監聽(listen),用accept()等待客戶端連線。     2)客戶端:socker()建立套接字,連線(connect)伺服器,連線上後使用send()和recv(

C# Socket簡單例子伺服器客戶通訊

這個例子只是簡單實現瞭如何使用 Socket 類實現面向連線的通訊。 注意:此例子的目的只是為了說明用套接字寫程式的大概思路,而不是實際專案中的使用程式。在這個例子中,實際上還有很多問題沒有解決,如訊息邊界問題、埠號是否被佔用、訊息命令的解析問題等。。 下面是兩個

linux下socket程式設計實現一個伺服器連線客戶

使用socekt通訊一般步驟     1)伺服器端:socker()建立套接字,繫結(bind)並

Linux下網路socket程式設計——實現伺服器select客戶通訊

Linux下網路socket程式設計——實現伺服器(select)與多個客戶端通訊 置頂 2017年06月23日 14:44:37 閱讀數:3225 標籤: socket程式設計伺服器與多個客戶端通epoll多路複用C語言網路程式設計 更多

一個伺服器客戶連線

為了使一個伺服器端能被多個客戶端連線我們採用執行緒的方法,伺服器建立一個執行緒之後,開啟的套接字就被執行緒所繼承,執行緒可以和連線的客戶進行通訊,而主執行緒(主伺服器)可以繼續接受以後的客戶連線,即Ac

java網路程式設計:9、基於TCP的socket程式設計伺服器迴圈監聽接收客戶_執行緒伺服器程式

宣告:本教程不收取任何費用,歡迎轉載,尊重作者勞動成果,不得用於商業用途,侵權必究!!! 文章目錄 一、核心程式碼編寫 1、伺服器端程式的編寫 2、客戶端程式的編寫 3、測試列印輸出 二、系列文章(java網路程式設計) 上篇講了基於tcp的程式設計的一些基礎知識

Java Socket客戶伺服器通訊

client程式碼: package com.cqut.test4; import java.io.*; import java.net.Socket; import java.net.SocketException; import java.net.U

linux下socket實現客戶伺服器的通訊

學習完《UNIX環境高階程式設計》套接字一章的內容之後,自己實現了單個客戶端與伺服器的通訊程式,後面想想要是多個客戶端如何與伺服器通訊呢?這就有了這篇文章。 伺服器端程式: #include<stdio.h> #include <stdlib.h&g

Linux c==TCP的客戶連線伺服器 (20)

通過父子程序實現TCP的多個客戶端連線伺服器 tcp_sever_fork.c #include <stdio.h> #include <string.h> #i

go語言基礎 TCP程式設計 結合Goroutine 客戶訪問一個伺服器

我們平時可以多個使用者往一個伺服器中上傳檔案,這是可以通過TCP程式設計來做到的,我們只要結合go語言的併發,就可以做到先是伺服器package main import ( "net" "

Windows Socket 程式設計_單個伺服器客戶簡單通訊

單個伺服器對多個客戶端程式: 一。簡要說明 二。檢視效果 三。編寫思路 四。程式原始碼 五。存在問題 一。簡要說明:  程式名為:TcpSocketOneServerToMulClient  程式功能:實現單個伺服器對多個客戶端通訊功能的小程式。 PS: 這是繼上次簡單的

boost::asio伺服器處理客戶連線(客戶程式)

//客戶端程式 // //  main.cpp //  tcpserver //  Created by suxianbin on 2018/9/15. //  Copyright © 2018 suxianbin. All rights