1. 什么是 Socket?
Socket编程是网络通信的基础,它允许不同主机间通过网络进行数据传输。通过套接字(socket),应用程序可以发送和接收数据,实现客户端与服务器之间的通信。套接字(socket)是支持网络通信的API,它为不同进程之间提供了一种基于网络的通信机制。
2. TCP 和 UDP 有什么区别?
TCP 和 UDP 都是传输层协议,但有一些显著的区别:
-
TCP:
- 面向连接(可靠的连接)。
- 确保数据包按顺序到达。
- 有错误校验和重传机制。
- 需要进行三次握手(TCP连接的建立)和四次挥手(连接的关闭)。
-
UDP:
- 无连接(不保证可靠性)。
- 数据包的顺序不能保证,可能会丢失。
- 不进行连接建立,效率较高。
- 常用于视频流、语音通话等对延迟敏感的应用。
3. 什么是套接字(Socket)编程中的“阻塞”与“非阻塞”?
- 阻塞模式:调用
recv()
、send()
等函数时,如果没有数据或无法发送数据,程序会被阻塞,直到操作完成为止。 - 非阻塞模式:调用
recv()
、send()
等函数时,如果没有数据或无法立即发送数据,程序会立刻返回,避免阻塞,可以通过select()
或poll()
等机制来判断是否可以进行操作。
4. TCP 套接字编程
TCP套接字通常用于需要可靠传输的应用程序,例如Web服务器、邮件服务等。
服务器端代码示例
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int server_fd, new_socket;struct sockaddr_in address;int addr_len = sizeof(address);char buffer[BUFFER_SIZE] = {0};// 创建socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("Socket failed");exit(EXIT_FAILURE);}// 配置服务器地址address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// 绑定socket到地址if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("Bind failed");exit(EXIT_FAILURE);}// 开始监听if (listen(server_fd, 3) < 0) {perror("Listen failed");exit(EXIT_FAILURE);}std::cout << "Server listening on port " << PORT << std::endl;// 接受客户端连接if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addr_len)) < 0) {perror("Accept failed");exit(EXIT_FAILURE);}// 读取客户端消息read(new_socket, buffer, BUFFER_SIZE);std::cout << "Message from client: " << buffer << std::endl;// 发送响应const char* message = "Hello from server";send(new_socket, message, strlen(message), 0);std::cout << "Message sent to client" << std::endl;close(new_socket);close(server_fd);return 0;
}
客户端代码示例
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sock = 0;struct sockaddr_in server_address;char buffer[BUFFER_SIZE] = {0};// 创建socketif ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}server_address.sin_family = AF_INET;server_address.sin_port = htons(PORT);// 将IPv4地址转换为二进制格式if (inet_pton(AF_INET, "127.0.0.1", &server_address.sin_addr) <= 0) {perror("Invalid address or Address not supported");exit(EXIT_FAILURE);}// 连接服务器if (connect(sock, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) {perror("Connection failed");exit(EXIT_FAILURE);}// 发送消息到服务器const char* message = "Hello from client";send(sock, message, strlen(message), 0);std::cout << "Message sent to server" << std::endl;// 读取服务器响应read(sock, buffer, BUFFER_SIZE);std::cout << "Message from server: " << buffer << std::endl;close(sock);return 0;
}
5. UDP 套接字编程
UDP套接字通常用于需要快速传输但不要求可靠性的应用程序,例如视频流、游戏等。
服务器端代码示例
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);char buffer[BUFFER_SIZE];// 创建socketif ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 绑定socketif (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {perror("Bind failed");exit(EXIT_FAILURE);}std::cout << "Server listening on port " << PORT << std::endl;while (true) {// 接收客户端消息int n = recvfrom(sockfd, (char*)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&client_addr, &addr_len);buffer[n] = '\0';std::cout << "Client message: " << buffer << std::endl;// 发送响应const char* response = "Hello from server";sendto(sockfd, response, strlen(response), MSG_CONFIRM, (const struct sockaddr*)&client_addr, addr_len);std::cout << "Response sent to client" << std::endl;}close(sockfd);return 0;
}
客户端代码示例
#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main() {int sockfd;struct sockaddr_in server_addr;char buffer[BUFFER_SIZE];// 创建socketif ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);server_addr.sin_addr.s_addr = INADDR_ANY;// 发送消息到服务器const char* message = "Hello from client";sendto(sockfd, message, strlen(message), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr));std::cout << "Message sent to server" << std::endl;// 接收服务器响应int n = recvfrom(sockfd, (char*)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&server_addr, nullptr);buffer[n] = '\0';std::cout << "Message from server: " << buffer << std::endl;close(sockfd);return 0;
}
总结
- TCP套接字适用于需要保证数据传输可靠性的应用,如Web服务、邮件服务等。
- UDP套接字适用于对数据传输速度要求较高、可以容忍丢包的应用,如视频流、游戏等。
在实际应用中,选择TCP或UDP取决于具体的应用场景及需求。TCP适用于对数据可靠性有严格要求的场景,UDP适用于对速度要求较高、能容忍丢包的场景。
笔记记录;