基于windowns下的TCP网络通信编程

Tcp通信的三次握手和四次挥手

TCP的三次握手和四次挥手是TCP连接的建立和断开过程,确保了可靠的数据传输和连接状态的正确管理。

TCP****的三次握手(TCP 链接建立):
  1. 客户端发送 SYN 客户端向服务器发送一个 SYN 报文段( SYN=1 , Seq=x ),表示请求建立连接。
  2. 服务器发送 SYN+ACK 服务器收到 SYN 报文段后,如果同意建立连接,则会发送一个 SYN+ACK 报文段( SYN=1 , ACK=x+1 , Seq=y ),表示确认客户端的请求,并表示自己也想建立连接。
  3. 客户端发送 ACK 客户端收到服务器的 SYN+ACK 报文段后,会发送一个确认报文段( ACK=1 , ACK=y+1 , Seq=x+1 ),表示确认收到服务器的确认,连接建立成功。
TCP****的四次挥手(TCP 链接断开):
  1. 客户端发送 FIN 客户端请求断开连接,发送一个 FIN 报文段( FIN=1 , Seq=x )。
  2. 服务器发送 ACK 服务器收到客户端的 FIN 报文段后,会发送一个确认报文段( ACK=1 , ACK=x+1 , Seq=y ),表示收到了客户端的请求,但是还有数据需要发送。
  3. 服务器发送 FIN 服务器发送完所有数据后,会发送一个 FIN 报文段( FIN=1 , ACK=x+1 , Seq=y ),表示自己也准备断开连接。
  4. 客户端发送 ACK 客户端收到服务器的 FIN 报文段后,会发送一个确认报文段( ACK=1 , ACK=y+1 , Seq=x+1 ),表示确认收到服务器的请求,连接断开。

通过三次握手,客户端和服务器之间建立了可靠的双向连接。而通过四次挥手,双方断开了连接,确保数据传输的可靠性和正确性。

客户端:

  1. 初始化Winsock库: 在使用任何套接字编程功能之前,需要初始化 Winsock 库。可以使用 WSAStartup 函数来完成初始化。
  2. 创建套接字: 使用 socket 函数创建一个套接字。指定地址族为 AF_INET,类型为 SOCK_STREAM,协议为 IPPROTO_TCP。
  3. 设置服务器地址和端口: 创建一个 sockaddr_in 结构体,并设置其中的地址族、IP地址和端口号,用于连接服务器。
  4. 连接服务器: 使用 connect 函数连接到服务器。将创建的套接字和服务器地址作为参数传递给 connect 函数。
  5. 发送和接收数据: 使用 send 函数向服务器发送数据,并使用 recv 函数接收服务器的响应数据。
  6. 关闭套接字: 使用 closesocket 函数关闭套接字。
  7. 清理Winsock库: 在程序退出前,使用 WSACleanup 函数清理 Winsock 库的资源。
cpp 复制代码
#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")

int main() {
    // 初始化Winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    int wsOK = WSAStartup(ver, &wsData);
    if (wsOK != 0) {
        std::cerr << "Error: Can't initialize Winsock! Quitting" << std::endl;
        return 1;
    }

    // 创建socket
    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "Error: Can't create socket! Quitting" << std::endl;
        WSACleanup();
        return 1;
    }

    // 连接到服务器
    sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(54000);
    inet_pton(AF_INET, "127.0.0.1", &server.sin_addr);

    if (connect(clientSocket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
        std::cerr << "Error: Can't connect to server! Quitting" << std::endl;
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }

    // 发送和接收数据
    char buffer[4096];
    std::string userInput;
    do {
        std::cout << "Enter a message: ";

        std::getline(std::cin, userInput);

        int sendResult = send(clientSocket, userInput.c_str(), userInput.size() + 1, 0);
        if (sendResult != SOCKET_ERROR) {
            // 接收服务器回复
            memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
            int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
            if (bytesReceived > 0) {
                std::cout << "Server response: " << std::string(buffer, bytesReceived) << std::endl;
            }
        }
        else {
            std::cerr << "Error: Send failed! Quitting" << std::endl;
            break;
        }
    } while (userInput != "quit");

    // 关闭客户端socket
    closesocket(clientSocket);

    // 关闭Winsock
    WSACleanup();

    return 0;
}

服务端:

在Windows平台上创建TCP服务器的基本步骤:

  1. 初始化Winsock库: 在使用任何套接字编程功能之前,需要初始化 Winsock 库。可以使用 WSAStartup 函数来完成初始化。
  2. 创建套接字: 使用 socket 函数创建一个套接字。指定地址族为 AF_INET ,类型为 SOCK_STREAM ,协议为 IPPROTO_TCP
  3. 设置服务器地址和端口: 创建一个 sockaddr_in 结构体,并设置其中的地址族、IP地址和端口号,用于绑定服务器的地址和端口。
  4. 绑定地址和端口: 使用 bind 函数将套接字绑定到指定的地址和端口上。
  5. 监听连接请求: 使用 listen 函数开始监听来自客户端的连接请求。
  6. 接受连接: 使用 accept 函数接受客户端的连接请求,并创建一个新的套接字用于与客户端通信。在接受连接之前,服务器会阻塞在这一步,直到有客户端连接上来。
  7. 接收和发送数据: 使用新创建的套接字进行数据的接收和发送。可以使用 recv 函数接收来自客户端的数据,使用 send 函数发送数据给客户端。
  8. 关闭连接: 当通信完成后,使用 closesocket 函数关闭与客户端的连接。
  9. 关闭服务器套接字: 当服务器不再接受新的连接时,使用 closesocket 函数关闭服务器套接字。
cpp 复制代码
#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")

int main() {
    // 初始化Winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    int wsOK = WSAStartup(ver, &wsData);
    if (wsOK != 0) {
        std::cerr << "Error: Can't initialize Winsock! Quitting" << std::endl;
        return 1;
    }

    // 创建socket
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == INVALID_SOCKET) {
        std::cerr << "Error: Can't create socket! Quitting" << std::endl;
        WSACleanup();
        return 1;
    }

    // 绑定地址和端口
    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(54000);
    hint.sin_addr.S_un.S_addr = INADDR_ANY; // 监听所有网卡上的连接
    bind(serverSocket, (sockaddr*)&hint, sizeof(hint));

    // 开始监听
    listen(serverSocket, SOMAXCONN);

    // 接受连接
    sockaddr_in client;
    int clientSize = sizeof(client);
    SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);

    // 关闭服务器socket
    closesocket(serverSocket);

    // 接收和发送数据
    char buffer[4096];
    while (true) {
        memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
        int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
        if (bytesReceived == SOCKET_ERROR) {
            std::cerr << "Error in recv(). Quitting" << std::endl;
            break;
        }

        if (bytesReceived == 0) {
            std::cout << "Client disconnected" << std::endl;
            break;
        }

        std::cout << "Received: " << std::string(buffer, 0, bytesReceived) << std::endl;

        // Echo回消息给客户端
        send(clientSocket, buffer, bytesReceived, 0);
    }

    // 关闭客户端socket
    closesocket(clientSocket);

    // 关闭Winsock
    WSACleanup();

    return 0;
}
相关推荐
Prejudices2 分钟前
C++如何调用Python脚本
开发语言·c++·python
单音GG4 分钟前
推荐一个基于协程的C++(lua)游戏服务器
服务器·c++·游戏·lua
qing_04060321 分钟前
C++——多态
开发语言·c++·多态
孙同学_21 分钟前
【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”
开发语言·c++
安步当歌33 分钟前
【WebRTC】视频发送链路中类的简单分析(下)
网络·音视频·webrtc·视频编解码·video-codec
charlie1145141911 小时前
Qt Event事件系统小探2
c++·qt·拖放·事件系统
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++
小辛学西嘎嘎1 小时前
C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
c语言·开发语言·c++
米饭是菜qy1 小时前
TCP 三次握手意义及为什么是三次握手
服务器·网络·tcp/ip
yaoxin5211231 小时前
第十九章 TCP 客户端 服务器通信 - 数据包模式
服务器·网络·tcp/ip