winSocketServer

knight2023-09-01 14:47cppcpp

windows平台 socket server

winSocketServer.h
//
// Created by knight on 2023/9/1.
//

#pragma once

class WinSocket {
public:
    WinSocket();
    ~WinSocket();

    bool Start(int port);
    void Stop() const;
    [[nodiscard]] SOCKET Accept() const;

private:
    SOCKET serverSocket;

    static bool Initialize();
    static void Cleanup();
};
winSocketServer.cpp
//
// Created by knight on 2023/9/1.
//

#include <winsock.h>
#include <iostream>
#include "winSocketServer.h"

WinSocket::WinSocket(): serverSocket(INVALID_SOCKET) {};

WinSocket::~WinSocket() {
    Stop();
}

bool WinSocket::Start(int port) {
    if (!Initialize()) {
        std::cout << "Failed to initialize winsock" << std::endl;
        return false;
    }

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET) {
        std::cout << "Failed to create socket" << std::endl;
        Cleanup();
        return false;
    }

    // 设置 Socket 地址信息
    sockaddr_in serverAddr{};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cout << "Failed to bind socket" << std::endl;
        Cleanup();
        return false;
    }

    if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
        std::cout << "Failed to listen" << std::endl;
        Cleanup();
        return false;
    }

    std::cout << "Server started, waiting for client connections..." << std::endl;
    return true;
}

void WinSocket::Stop() const {
    closesocket(serverSocket);
    Cleanup();
}

bool WinSocket::Initialize() {
    WSADATA wsaData;
    return WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
}

void WinSocket::Cleanup() {
    WSACleanup();
}

SOCKET WinSocket::Accept() const {
    SOCKET clientSocket = accept(serverSocket, nullptr, nullptr);
    if (clientSocket == INVALID_SOCKET) {
        return INVALID_SOCKET;
    }
    return clientSocket;
}

main
int main() {
    // 初始化serverSocket
    bool startSocketFlag = winSocket.Start(端口号);
    if (!startSocketFlag) {
        return 1;
    }
    
	while (true) {
        SOCKET clientSocket = winSocket.Accept();
        if (clientSocket == INVALID_SOCKET) {
            continue;
        }

        // todo 处理与客户端的数据交互

        closesocket(clientSocket);
    }
}
如何对tcp链接身份进行认证?
/**
 * 身份认证信息读取
 * @param clientSocket
 * @return 身份认证信息字符串标识
 */
std::string identity(SOCKET clientSocket) {
    char identityBuffer[10];
    memset(identityBuffer, 0, sizeof(identityBuffer));
    recv(clientSocket, identityBuffer, sizeof(identityBuffer) - 1, 0);
    std::string identityStr(identityBuffer);
    return identityStr;
}
如何处理tcp粘包?

规定每包的长度与头尾

const int PACKET_LENGTH = 2407;
const char PACKET_START[] = {0x4d, 0x45, 0x50};
const char PACKET_END[] = {0x53, 0x4C, 0x44};

void packet(int clientSocket) {
     std::vector<char> buffer(PACKET_LENGTH);
     std::vector<char> receivedData;
     int dataSize = 0;
    
     while (true) {
        int bytesRead = recv(clientSocket, buffer.data(), PACKET_LENGTH, 0);
        if (bytesRead <= 0) {
            break;
        }
        // 追加接收到的数据到 receivedData
        receivedData.insert(receivedData.end(), buffer.begin(), buffer.begin() + bytesRead);
        dataSize += bytesRead;
        // 查找完整的包
        int headerIndex;  // 头部索引,用于记录找到的包的起始位置
        int packetSize;  // 包大小,用于记录找到的包的长度
        // // 如果数据大小比包长度小则继续接收
        if (dataSize < PACKET_LENGTH) {
            continue;
        }
        // 查找完整的包
        for (int i = 0; i < dataSize - PACKET_LENGTH; ++i) {
            if (receivedData[i] == PACKET_START[0] && receivedData[i + 1] == PACKET_START[1] &&
                receivedData[i + 2] == PACKET_START[2]) {
                // 找到了包起始位置
                headerIndex = i;
                packetSize = i + PACKET_LENGTH;

                // 在剩余数据中查找结束标记
                for (int j = packetSize; j <= dataSize - PACKET_LENGTH; ++j) {
                    if (receivedData[j] == PACKET_END[0] && receivedData[j + 1] == PACKET_END[1] &&
                        receivedData[j + 2] == PACKET_END[2]) {
                        // 找到了包的结束标记
                        packetSize = j + PACKET_LENGTH;
                        break;
                    }
                }

                // 处理完整的包
                if (packetSize - headerIndex == PACKET_LENGTH) {
                    
                    // todo 处理接收到的包数据
                    
                    // 更新接收到的数据和数据大小
                    receivedData.erase(receivedData.begin(), receivedData.begin() + packetSize);
                    dataSize = static_cast<int>(receivedData.size());
					
                    // 如果处理完数据比包长度小则结束该循环
                    if (dataSize < PACKET_LENGTH) {
                        break;
                    }

                    // 重新检查剩余数据中是否存在完整的包
                    i = -1;
                }
            }
        }
     }
}

Last Updated 8/16/2024, 6:38:40 AM