socket网络通信TCP与UDP原理及代码实现(c++、python)

目录

Socket原理

通信协议原理

TCP

UDP

代码实现

TCP

C++

python

UDP

C++

python


Socket原理

Socket(套接字)是计算机网络中用于实现进程间通信的一种机制,特别是在不同主机之间通过网络进行数据传输时。它是网络编程的核心概念之一,为应用程序提供了统一的接口,使得开发者可以通过网络发送和接收数据。可以将 Socket 类比为电话系统中的“电话机”。两台设备通过 Socket 建立连接后,就像两个人通过电话通话一样进行数据交换。

在网络通信中,最常用到的就是socket,可以实现不同协议,如TCP、UDP,的网络通信。一般采用客户端-服务器的工作模式。客户端是主动发送连接请求或者数据的一方,服务端是被动接收请求的一方,根据收到的客户端连接请求或数据,返回给客户端相应的数据,进行数据交换。通常包括以下步骤:

服务器端:

  1. 创建 Socket:服务器创建一个 Socket,并绑定到特定的 IP 地址和端口。

  2. 监听连接:服务器开始监听来自客户端的连接请求。

  3. 接受连接:当客户端发起连接请求时,服务器接受连接并创建一个新的 Socket 用于与客户端通信。

  4. 数据交换:通过 Socket 发送和接收数据。

  5. 关闭连接:通信完成后,关闭 Socket。

客户端:

  1. 创建 Socket:客户端创建一个 Socket。

  2. 发起连接:客户端向服务器的 IP 地址和端口发起连接请求。

  3. 数据交换:连接成功后,通过 Socket 发送和接收数据。

  4. 关闭连接:通信完成后,关闭 Socket。

通信协议原理

TCP(传输控制协议) 和 UDP(用户数据报协议) 是两种主要的传输层协议,用于在网络中传输数据。它们在原理、特性和适用场景上有显著差异。选择 TCP 还是 UDP 取决于具体的应用需求。

TCP

TCP 是一种面向连接的协议,提供可靠的、基于字节流的通信。核心特点是可靠性,确保数据能够完整、有序地传输。在传输数据前需要建立连接(三次握手),数据传输完成之后还要断开连接(四次挥手),其大致原理图如下:(图片来自于网络)

socket网络通信TCP与UDP原理及代码实现(c++、python)_第1张图片

socket网络通信TCP与UDP原理及代码实现(c++、python)_第2张图片

主要特点包括:

  • 可靠性:通过确认机制、重传机制和校验和确保数据不丢失、不重复、无错误。

  • 有序性:通过序列号保证数据按发送顺序到达。

  • 流量控制:通过滑动窗口机制防止发送方过快导致接收方缓冲区溢出。

  • 拥塞控制:通过动态调整发送速率避免网络拥塞。

当然,也存在着一些缺点,比如建立和断开连接需要额外开销,延迟较高;协议复杂,占用较多系统资源等。根据这些特性,TCP更适合对数据完整性要求高的场景,即希望数据能够准确无误得到达目的地,即使花费较多的时间,占用更多的资源也没有关系。一般文件传输、网页浏览、电子邮件、数据库访问都是使用的TCP协议。

UDP

UDP 是一种无连接的协议,提供简单的、基于数据报的通信。核心特点是高效性,但不保证可靠性。传输数据前不需要建立连接,直接发送数据即可,结束也不需要断开连接。

主要特点包括:

  • 无连接:无需建立连接,直接发送数据。

  • 不可靠性:不保证数据是否到达、是否有序、是否重复。

  • 高效性:协议简单,开销小,传输速度快。

  • 支持广播和多播:可以将数据发送给多个接收方。

其缺点也很明显:不能保证数据可靠性,可能丢失、重复或乱序,也不支持流量控制和拥塞控制。因为没有拥塞控制,所以在网络拥堵的情况下,UDP也能将数据送达,但是数据的完整性就没办法保证了。根据这些特性,UDP更适合对实时性要求高的场景,即希望数据能够更快速得到达目的地,即使数据内容可能会有一些错误也没有关系。一般视频通话、在线游戏、DNS 查询都是使用的UDP协议。

代码实现

代码都有详细注释,且提供了目前经常使用的c++和python两种实现方式。为了方便阅读和理解,代码仅实现了一些基本功能,可以根据实际需求,增删代码。

C++语言实现中,Windows系统和Linux系统的代码是有差别的,所以下面我将给出两个操作系统的代码版本。

TCP

C++

Linux服务端代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){

    //1. 创建socket
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 监听连接
    // 设置需要监听的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8000); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.54.121"); //设置ip

    // 绑定指定端口
    if (bind(serverSocket , (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
        cout << "bind error" << endl;
        return -1;
    }
 
    // 监听端口
    if (listen(serverSocket, 10) < 0) {
        cout << "listen error" << endl;
        return -1;
    }else cout << "waiting" << endl;
 
    //3. 接受连接
    int clientSocket = accept(serverSocket, NULL,NULL);
 
    //4. 数据交换
    while(true){  //一直循环等待接收数据,直到客户端断开连接
        // 接收客户端发来的数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        int ret = recv(clientSocket, buffer, 1024, 0);
        if (ret <= 0)break;
        cout << "Message from client: " << buffer << endl;
        
        // 返回响应给客户端
        strcpy(buffer, "ok");
        send(clientSocket, buffer, (int)strlen(buffer), 0);
        cout << "ok message sent" << endl;
    }
 
    //5. 关闭连接
    close(clientSocket);
    close(serverSocket);
    
    return 0;
}

Windows服务端代码

#include 
#include 
#pragma comment(lib, "ws2_32.lib")  //链接Winsock库
using namespace std;

int main(){
    // 初始化Winsock,开始网络权限
    WSADATA wasData;
    WSAStartup(MAKEWORD(2, 2), &wasData);

    //1. 创建socket
    SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 监听连接
    // 设置需要监听的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.43.126"); //设置ip

    // 绑定指定端口
    if (bind(serverSocket , (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
        cout << "bind error" << endl;
        return -1;
    }
 
    // 监听端口
    if (listen(serverSocket, 10) < 0) {
        cout << "listen error" << endl;
        return -1;
    }else cout << "waiting" << endl;
 
    //3. 接受连接
    SOCKET clientSocket = accept(serverSocket, NULL, NULL);
 
    //4. 数据交换
    while(true){  //一直循环等待接收数据,直到客户端断开连接
        // 接收客户端发来的数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        int ret = recv(clientSocket, buffer, 1024, 0);
        if (ret <= 0)break;
        cout << "Message from client: " << buffer << endl;
        
        // 返回响应给客户端
        strcpy(buffer, "ok");
        send(clientSocket, buffer, (int)strlen(buffer), 0);
        cout << "ok message sent" << endl;
    }
 
    //5. 关闭连接
    closesocket(clientSocket);
    closesocket(serverSocket);
    
    return 0;
}

Linux客户端代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){

    //1. 创建socket
    int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 发起连接
    // 设置服务器的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8000); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.54.121"); //设置ip
    
    // 给服务器发送连接请求
    if (connect(clientSocket, (struct sockaddr*)&Addr, sizeof(Addr)) < 0) {
	    cout << "connect error" << endl;
	    close(clientSocket);
	    return -1;
    }
 
    //3. 数据交换
    int i=0;
    while(i<10){  //发送10次数据后就退出
        // 给服务端发送数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        strcpy(buffer, "hello");
	    send(clientSocket, buffer, (int)strlen(buffer), 0);
    
        // 接收服务端的响应数据
	    int ret = recv(clientSocket, buffer, 1024, 0);
	    if (ret <= 0)break;
	    cout << "Message from client: " << buffer << endl;
        i++;
    }
 
    //4. 关闭连接
    close(clientSocket);
    
    return 0;
}

Windows客户端代码:

#include 
#include 
#pragma comment(lib, "ws2_32.lib")  //链接Winsock库
using namespace std;

int main(){
    // 初始化Winsock,开始网络权限
    WSADATA wasData;
    WSAStartup(MAKEWORD(2, 2), &wasData);

    //1. 创建socket
    SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (clientSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 发起连接
    // 设置服务器的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.43.126"); //设置ip
    
    // 给服务器发送连接请求
    if (connect(clientSocket, (struct sockaddr*)&Addr, sizeof(Addr)) < 0) {
	    cout << "connect error" << endl;
	    closesocket(clientSocket);
	    return -1;
    }
 
    //3. 数据交换
    int i=0;
    while(i<10){  //发送10次数据后就退出
        // 给服务端发送数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        strcpy(buffer, "hello");
	    send(clientSocket, buffer, (int)strlen(buffer), 0);
    
        // 接收服务端的响应数据
	    int ret = recv(clientSocket, buffer, 1024, 0);
	    if (ret <= 0)break;
	    cout << "Message from client: " << buffer << endl;
        i++;
    }
 
    //4. 关闭连接
    closesocket(clientSocket);
    
    return 0;
}

python

服务端代码:

import socket 

#1. 创建Socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#2. 监听连接
#绑定端口
ip = "10.12.43.126" 
port = 8080
socket_server.bind((ip, port))
#开始监听
socket_server.listen()
print("waiting at "+ip+":"+str(port))

#3. 接受连接
client_socket, client_address = socket_server.accept()
print('connect:', client_address)

#4. 数据交换
while True: #一直等待客户端发送数据,直到断开连接
    # 接收客户端发来的数据
    receive = client_socket.recv(1024)
    if not receive:
        break
    print("receive:"+receive.decode())

    # 响应客户端数据
    re = "ok"
    client_socket.send(re.encode())

#5. 关闭连接
client_socket.close()
socket_server.close()

客户端代码:

import socket 

#1. 创建Socket
socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

#2. 发起连接
ip = "10.12.43.126"
port = 8080
socket_client.connect((ip,port))
print("connect"+ip+":"+str(port))

#3. 数据交换
i=0
while i<10: #发送10次数据后就退出
    # 给服务端发送数据
    message = "hello"
    socket_client.send(message.encode())

    # 接收服务端的响应数据
    response = socket_client.recv(1024)
    print("receive:"+ response.decode())
    i=i+1

#4. 关闭连接
socket_client.close()

UDP

C++

Linux服务端代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){

    //1. 创建socket
    int serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (serverSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 监听数据接收端口
    // 设置需要监听的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.54.121"); //设置ip

    // 绑定指定端口
    if (bind(serverSocket , (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
        cout << "bind error" << endl;
        return -1;
    }else cout << "waiting at IP: " << inet_ntoa(Addr.sin_addr)<< " Port: " << ntohs(Addr.sin_port) << endl;

    //3. 数据交换
    while(true){  //一直循环等待接收数据
        // 接收客户端发来的数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        struct sockaddr_in client_addr; //记录客户端的IP地址
        socklen_t client_len = sizeof(client_addr);
        int ret = recvfrom(serverSocket, buffer, 1024, 0, (struct sockaddr *) &client_addr, &client_len);
        if (ret <= 0)break;
        cout << "Message from client: " << buffer << endl;
        
        // 返回响应给客户端
        strcpy(buffer, "ok");
        sendto(serverSocket, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, client_len);
        cout << "ok message sent" << endl;
    }
 
    //4. 关闭连接
    close(serverSocket);
    
    return 0;
}

Windows服务端代码:

#include 
#include 
#pragma comment(lib, "ws2_32.lib")  //链接Winsock库
using namespace std;

int main(){
    // 初始化Winsock,开始网络权限
    WSADATA wasData;
    WSAStartup(MAKEWORD(2, 2), &wasData);

    //1. 创建socket
    SOCKET serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (serverSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 监听数据接收端口
    // 设置需要监听的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.43.126"); //设置ip

    // 绑定指定端口
    if (bind(serverSocket , (struct sockaddr *)&Addr, sizeof(Addr)) < 0) {
        cout << "bind error" << endl;
        return -1;
    }else cout << "waiting at IP: " << inet_ntoa(Addr.sin_addr)<< " Port: " << ntohs(Addr.sin_port) << endl;
 
    //3. 数据交换
    while(true){  //一直循环等待接收数据
        // 接收客户端发来的数据
        char buffer[1024] = { 0 };  //存放数据的缓存
        struct sockaddr_in clientAddr;  //记录客户端的IP地址
        int clientAddrLen = sizeof(clientAddr);
        memset(&clientAddr, 0, sizeof(clientAddr));
        int ret = recvfrom(serverSocket, buffer, 1024, 0, (struct sockaddr*)&clientAddr, &clientAddrLen);  //直接接收数据,无需建立连接
        if (ret <= 0)break;
        cout << "Message from client: " << buffer << endl;
        
        // 返回响应给客户端
        strcpy(buffer, "ok");
        sendto(serverSocket, buffer, 1024, 0, (struct sockaddr*)&clientAddr, clientAddrLen);
        cout << "ok message sent" << endl;
    }
 
    //4. 关闭连接
    closesocket(serverSocket);
    
    return 0;
}

Linux客户端代码:

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){

    //1. 创建socket
    int clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (clientSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 数据交换
    // 设置服务器的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.54.121"); //设置ip
    
    // 发送和接收数据
    while(true){
        // 给服务端发送数据
        string message;
		cout << "Enter message: "; 
		getline(cin, message); //手动输入要发送的数据
	    sendto(clientSocket,message.c_str(), message.size(), 0, (struct sockaddr*)&Addr, sizeof(Addr)); //直接发送数据,无需建立连接

        // 接收服务端的响应数据
        char buffer[1024] = { 0 };;
        socklen_t AddrSize = sizeof(Addr);
	    int ret = recvfrom(clientSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&Addr, &AddrSize);
	    if (ret <= 0)break;
	    cout << "Message from server: " << buffer << endl;
    }
 
    //3. 关闭连接
    close(clientSocket);
    
    return 0;
}

Windows客户端代码:

#include 
#include 
#pragma comment(lib, "ws2_32.lib")  //链接Winsock库
using namespace std;

int main(){
    // 初始化Winsock,开始网络权限
    WSADATA wasData;
    WSAStartup(MAKEWORD(2, 2), &wasData);

    //1. 创建socket
    SOCKET clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if (clientSocket < 0){  //判断是否创建成功
        cout << "socket error" << endl;
        return -1;
    }

    //2. 数据交换
    // 设置服务器的ip地址和端口
    struct sockaddr_in Addr;
    memset(&Addr, 0, sizeof(Addr));
    Addr.sin_family = AF_INET;  //IPv4
    Addr.sin_port = htons(8080); //设置端口
    Addr.sin_addr.s_addr = inet_addr("10.12.43.126"); //设置ip

    // 发送和接收数据
    while(true){
        // 给服务端发送数据
        string message;
		cout << "Enter message: "; 
		getline(cin, message); //手动输入要发送的数据
	    sendto(clientSocket,message.c_str(), message.size(), 0, (struct sockaddr*)&Addr, sizeof(Addr)); //直接发送数据,无需建立连接

        // 接收服务端的响应数据
        char buffer[1024] = { 0 };;
        int AddrSize = sizeof(Addr);
	    int ret = recvfrom(clientSocket, buffer, 1024, 0, (struct sockaddr*)&Addr, &AddrSize);
	    if (ret <= 0)break;
	    cout << "Message from server: " << buffer << endl;
    }
 
    //3. 关闭连接
    closesocket(clientSocket);
    
    return 0;
}

python

服务端代码:

import socket 

#1. 创建Socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#2. 监听数据接收端口
#绑定端口
ip = "10.12.43.126" 
port = 8080
socket_server.bind((ip, port))

#3. 数据交换
while True: #一直等待客户端发送数据
    # 接收客户端发来的数据
    receive,addr = socket_server.recvfrom(1024)
    if not receive:
        break
    print("receive:"+receive.decode())

    # 响应客户端数据
    re = "ok"
    socket_server.sendto(re.encode(),addr)

#4. 关闭连接
socket_server.close()

客户端代码:

import socket 

#1. 创建Socket
socket_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#2. 数据交换
# 设置服务器的ip地址和端口
ip = "10.12.43.126"
port = 8080

# 发送和接收数据
while True: 
    # 给服务端发送数据
    message = input("Enter message: ")
    socket_client.sendto(message.encode(),(ip,port))

    # 接收服务端的响应数据
    response,_ = socket_client.recvfrom(1024)
    print("receive:"+ response.decode())

#3. 关闭连接
socket_client.close()

你可能感兴趣的:(socket网络通信TCP与UDP原理及代码实现(c++、python))