C++的socket編程學習


前言

  不得不承認作為一個前端開發,仍有一個后台開發的夢。從socket通信開始學習,在工作之余補充學習點相關知識,記錄下學習的過程。

服務端

  服務器代碼如下,在設置listen之后,通過accept獲取對應的socket連接並創建線程進行通信,通信完成后關閉對應線程。

// socket_service.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h" 
#include <stdio.h>
#include <Winsock2.h>
#pragma comment(lib, "ws2_32.lib")

#define LISTEN_MAX_COUNT 5

DWORD WINAPI AnswerThread(LPVOID lparam)
{
    printf("Thread ID:%4d create!\n", GetCurrentThreadId());
    int                 ret;
    char                buf[50] = { 0 };
    char                sendBuf[80] = { 0 };
    SOCKET              clientSocket = (SOCKET)(LPVOID)lparam;
    while (true)
    {
        memset(buf, 0, sizeof(buf));
        ret = recv(clientSocket, buf, sizeof(buf), 0);
        if (ret<=0)
        {
            break;
        }
        printf("revc: %s\n", buf);
        sprintf_s(sendBuf, "Thread ID:%4d revced", GetCurrentThreadId());
        ret = send(clientSocket, sendBuf, strlen(sendBuf) + sizeof(char), 0);
        if (ret <= 0)
        {
            break;
        }
    }
    printf("Thread ID:%4d stop!\n", GetCurrentThreadId());
    closesocket(clientSocket);
    return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{

    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(1, 1);
    if (WSAStartup(wVersionRequested, &wsaData) == INVALID_SOCKET)
    {
        return 0;
    }

    if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return 0;
    }
    SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
    int len = sizeof(SOCKADDR);
    SOCKADDR_IN clientAddr;
    SOCKADDR_IN serviceAddr;
    serviceAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    serviceAddr.sin_family = AF_INET;
    serviceAddr.sin_port = htons(27015);
    
    if (bind(sockSrv, (SOCKADDR*)&serviceAddr, len) == INVALID_SOCKET)
    {
        printf("failed bind!\n");
        closesocket(sockSrv);
        WSACleanup();
        return 0;
    }
    if (listen(sockSrv, LISTEN_MAX_COUNT) == SOCKET_ERROR) {
        printf("Listen failed with error: %ld\n", WSAGetLastError());
        closesocket(sockSrv);
        WSACleanup();
        return 0;
    }

     
    SOCKET  sockClient;
    HANDLE  hThread = NULL;
    DWORD    dwThreadId;
    while (1)
    {
        sockClient = accept(sockSrv, (SOCKADDR*)&clientAddr, &len);
        Sleep(1000);
        hThread = CreateThread(NULL, NULL, AnswerThread, (LPVOID)sockClient, 0, &dwThreadId);
        if (hThread == NULL)
        {
            printf("CreatThread AnswerThread() failed.\n");
        }
    }

    closesocket(sockSrv);
    WSACleanup();
    return 0;
}

 

客戶端

   客戶端代碼如下,在連接成功后,循環輸入進行通信對話。

// socket_client.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include <stdio.h>
#include <Winsock2.h>

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

int _tmain(int argc, _TCHAR* argv[])
{
     
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;

    wVersionRequested = MAKEWORD(1, 1);
    if (WSAStartup(wVersionRequested, &wsaData) == INVALID_SOCKET)
    {
        return -1;
    }

    if (LOBYTE(wsaData.wVersion) != 1 ||
        HIBYTE(wsaData.wVersion) != 1) {
        WSACleanup();
        return -1;
    }


    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    int len = sizeof(SOCKADDR);

    SOCKADDR_IN local;
    local.sin_addr.S_un.S_addr = inet_addr("192.168.1.15");
    local.sin_family = AF_INET;
    local.sin_port = htons(27015);

    if (connect(sockClient, (SOCKADDR*)&local, len) == INVALID_SOCKET)
    {
        printf("connect error/n"); 
        return 0;
    }

    char inputBuf[30];
    char recvBuf[50];
    int ret;
//    while (scanf_s("%s", inputBuf, sizeof(inputBuf)) != EOF)
    while (gets_s(inputBuf))
    {
        if (strcmp(inputBuf, "stop") ==0)
        {
            break;
        }
        ret = send(sockClient, inputBuf, strlen(inputBuf) + sizeof(char), 0);
        if (ret<=0)
        {
            printf("send failed!\n");
            break;
        }
        ret = recv(sockClient, recvBuf, sizeof(recvBuf), 0);
        if (ret <= 0)
        {
            printf("recv failed!\n");
            break;
        }
        printf("my reply is : %s\n", recvBuf);
        //printf("%s\n", inet_ntoa(local.sin_addr));
    }

    closesocket(sockClient);
    WSACleanup();
    return 0;
}

 

測試

  Hello World!!

1、開啟多個客戶端,可以看到服務器如下輸出多個線程的創建。

  

2、客戶端輸入hello world!,可以得到服務器回復,並告知哪個服務器線程接收了消息。

  

3、關閉其中一個客戶端,可以看到對應線程也關閉了。

4、關閉服務端后,可以端輸入任意內容,可以看到客戶端也收到提示發送失敗並關閉。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM