基于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;
}
相关推荐
sone121389 分钟前
计算机网络(第8版)第四章 网络层(4.7.1~4.7.3)
服务器·网络·计算机网络
ladymorgana34 分钟前
【运维笔记】windows 11 中提示:无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。
运维·windows·笔记
过过过呀Glik1 小时前
在 Ubuntu 上安装 Muduo 网络库的详细指南
linux·c++·ubuntu·boost·muduo
m0_748238271 小时前
WebClient HTTP 请求问题处理模板(泛型响应、忽略 SSL 证书等)
网络协议·http·ssl
0zxm1 小时前
06 - Django 视图view
网络·后端·python·django
蜀黍@猿2 小时前
【C++ 基础】从C到C++有哪些变化
c++
Am心若依旧4092 小时前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
zh路西法2 小时前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(一):从电梯出发的状态模式State Pattern
c++·决策树·状态模式
୧⍢⃝୨ LonelyCoder2 小时前
FreePBX修改IP地址和端口以及添加SSL证书开启HTTPS访问
tcp/ip·https·ssl
轩辰~2 小时前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议