欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > C++ 之 SOCKET 通信详解

C++ 之 SOCKET 通信详解

2025/5/21 4:52:40 来源:https://blog.csdn.net/yohnyang/article/details/146538577  浏览:    关键词:C++ 之 SOCKET 通信详解

C++ 之 SOCKET 通信详解

  • SOCKET中首先我们要理解如下几个定义概念:

    • 一是IP地址:IP Address, 就是依照TCP/IP协议分配给本地主机的网络地址, 比如两个进程要通讯,任一进程要知道通讯对方的位置,就用对方的IP。
    • 二是端口号: 用来标识本地通讯进程,方便OS提交数据.就是说进程指定了对方进程的网络IP,但这个IP只是用来标识进程所在的主机,如何来找到运行在这个主机的这个进程呢,就用端口号。
    • 三是连接: 指两个进程间的通讯链路
    • 四是半相关: 网络中用一个三元组可以在全局唯一标志一个进程:(协议,本地地址,本地端口号)
    • 五是全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:(协议,本地地址,本地端口号,远地地址,远地端口号)
  • 运行模式:

    • 在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器模式(Client/Server model),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务。
    • 客户/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是客户/服务器模式的TCP/IP。
  • 下面详细总结一下 SOCKET 相关原理

1. SOCKET 基础

  • Socket 是计算机网络中的端点,客户端和服务器通过Socket进行通信。每个Socket都是由操作系统提供的一个API,它封装了网络协议栈的各种细节,程序通过调用Socket相关函数来完成数据的发送和接收。

  • Socket的类型在网络编程中,主要有两种Socket类型:

    • TCP Socket (SOCK_STREAM):面向连接的可靠通信。数据以流的形式传输,适用于要求可靠性、顺序传输的应用(如HTTP、FTP等)。
    • UDP Socket (SOCK_DGRAM):无连接的、不可靠的通信方式。数据报文独立发送,不保证顺序、可靠性,适用于对实时性要求较高但对丢包可以容忍的场景(如DNS、视频流、实时游戏等)。
  • Socket是网络通信端点,TCP协议提供可靠连接(类似打电话),UDP协议提供无连接服务(类似发短信)。TCP服务端与客户端通信流程如下:
    在这里插入图片描述

2. 编程步骤

1. 创建Socket

  • 首先需要调用 socket() 函数来创建一个Socket。socket() 函数的原型如下:
int socket(int domain, int type, int protocol);

domain:指定协议族,通常是 AF_INET(IPv4)或者 AF_INET6(IPv6)。
type:指定Socket的类型,通常为 SOCK_STREAM(TCP)或者 SOCK_DGRAM(UDP)。
protocol:指定使用的协议,一般可以设置为0,操作系统会自动选择合适的协议。

  • 例如,创建一个TCP Socket:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {perror("socket creation failed");exit(1);
}

2. 绑定Socket(bind)

  • 创建Socket之后,需要将其与特定的地址(IP地址和端口)绑定。这一步骤通常在服务器端进行,以便监听某个特定的端口。使用 bind() 函数绑定Socket
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;  // 监听所有的网络接口
server_addr.sin_port = htons(8080);        // 设置端口号if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("bind failed");exit(1);
}

3. 监听Socket(listen) & 接受连接(accept)

  • 对于TCP连接,服务器端需要监听并等待客户端的连接请求。可以使用 listen()accept() 函数来实现:
if (listen(sockfd, 5) < 0) {perror("listen failed");exit(1);
}int new_sock = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
if (new_sock < 0) {perror("accept failed");exit(1);
}

4. 连接到服务器(connect)

  • 客户端通过 connect() 函数与服务器建立连接。它需要指定服务器的IP地址和端口:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("connect failed");exit(1);
}

5. 数据发送与接收(send/recv)

  • 在连接建立之后,客户端和服务器就可以通过 send()recv() 函数进行数据传输。对于UDP,使用 sendto()recvfrom()

    • send():将数据发送到Socket。
    • recv():从Socket接收数据。
char message[] = "Hello, World!";
if (send(new_sock, message, sizeof(message), 0) < 0) {perror("send failed");exit(1);
}char buffer[1024];
int n = recv(new_sock, buffer, sizeof(buffer), 0);
if (n < 0) {perror("recv failed");exit(1);
}
buffer[n] = '\0';
printf("Received message: %s\n", buffer);

6. 关闭Socket(close)

  • 通信完成后,需要关闭Socket以释放资源:
close(sockfd);
close(new_sock);

3. 一个简单的C++ TCP服务器和客户端

  • 服务端
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>int main() {int server_fd, new_sock;struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);char buffer[1024];server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {perror("Socket creation failed");exit(1);}server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(8080);if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Bind failed");exit(1);}if (listen(server_fd, 5) < 0) {perror("Listen failed");exit(1);}std::cout << "Waiting for client connection..." << std::endl;new_sock = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);if (new_sock < 0) {perror("Accept failed");exit(1);}std::cout << "Client connected!" << std::endl;int n = recv(new_sock, buffer, sizeof(buffer), 0);if (n < 0) {perror("Receive failed");exit(1);}buffer[n] = '\0';std::cout << "Received: " << buffer << std::endl;close(new_sock);close(server_fd);return 0;
}
  • 客户端
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>int main() {int sockfd;struct sockaddr_in server_addr;char message[] = "Hello from client!";sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {perror("Socket creation failed");exit(1);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Connection failed");exit(1);}if (send(sockfd, message, sizeof(message), 0) < 0) {perror("Send failed");exit(1);}close(sockfd);return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词