一、核心概念
-
Socket:
网络套接字,由IP+端口号+协议唯一标识。
在Linux中,Socket被抽象为文件描述符,可通过文件操作函数进行数据收发。 -
协议类型:
TCP:面向连接、可靠传输,保证数据有序、不丢失。
UDP:无连接、不可靠传输,直接发送数据,效率高但可能丢失。 -
字节序:
网络传输必须使用大端字节序,而主机可能是大端或小端,需通过htons()、ntohs()等函数转换。
二、TCP的三次握手和四次挥手
TCP三次握手:建立连接
-
SYN:客户端发送一个 SYN包,请求建立连接。
-
SYN-ACK:服务器回复 SYN-ACK,表示同意建立连接。
-
ACK:客户端再发送一个 ACK 包,连接建立完成。
TCP 四次挥手:断开连接
-
FIN:主动方发送 FIN,表示“我不再发送数据”。
-
ACK:被动方回复 ACK,确认收到。
-
FIN:被动方也发送 FIN,表示“我也不再发送数据”。
-
ACK:主动方回复 ACK,连接彻底关闭。
三、关键函数说明
| 函数 | 作用 | 常用参数 |
|---|---|---|
socket() | 创建 Socket 描述符 | domain(协议族,如 AF_INET)、type(SOCK_STREAM/SOCK_DGRAM) |
bind() | 绑定地址和端口 | Socket 描述符、sockaddr 结构体(含IP和端口)、地址长度 |
listen() | 监听 TCP 连接 | Socket 描述符、等待队列长度 |
accept() | 接受 TCP 连接 | 监听 Socket 描述符、输出客户端地址、地址长度 |
connect() | TCP 客户端连接服务器 | Socket 描述符、服务器sockaddr结构体、地址长度 |
send()/recv() | TCP 收发数据 | Socket 描述符、数据缓冲区、长度、标志(通常为 0) |
sendto()/recvfrom() | UDP 收发数据 | 比TCP多一个参数:目标或源地址结构体及长度 |
close() | 关闭 Socket 连接 | Socket 描述符 |
四、TCP通信代码实例
1.服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
const char *response = "Hello from server";
// 1. 创建 TCP Socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 设置地址结构
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 3. 绑定Socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 4. 监听连接,最大等待队列长度3
if (listen(server_fd, 3) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", PORT);
// 5. 接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept failed");
exit(EXIT_FAILURE);
}
printf("Client connected\n");
// 6. 读取客户端数据
read(new_socket, buffer, BUFFER_SIZE);
printf("Received from client: %s\n", buffer);
// 7. 向客户端发送响应
send(new_socket, response, strlen(response), 0);
printf("Response sent\n");
// 8. 关闭连接
close(new_socket);
close(server_fd);
return 0;
}
2.客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE] = {0};
const char *message = "Hello from client";
// 1. 创建 TCP Socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("invalid address");
exit(EXIT_FAILURE);
}
// 3. 连接服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("connection failed");
exit(EXIT_FAILURE);
}
// 4. 向服务器发送数据
send(sock, message, strlen(message), 0);
printf("Message sent\n");
// 5. 读取服务器响应
read(sock, buffer, BUFFER_SIZE);
printf("Received from server: %s\n", buffer);
// 6. 关闭连接
close(sock);
return 0;
}
五、UDP通信代码实例
1.服务器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock_fd;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len = sizeof(cli_addr);
char buffer[BUFFER_SIZE] = {0};
const char *response = "Hello from UDP server";
// 1. 创建 UDP Socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(PORT);
// 3. 绑定地址和端口
if (bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("UDP server listening on port %d...\n", PORT);
// 4. 接收客户端数据
int n = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cli_addr, &cli_len);
buffer[n] = '\0';
printf("Received from client: %s\n", buffer);
// 5. 向客户端发送响应
sendto(sock_fd, response, strlen(response), 0, (struct sockaddr *)&cli_addr, cli_len);
printf("Response sent\n");
// 6. 关闭 Socket
close(sock_fd);
return 0;
}
2.客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock_fd;
struct sockaddr_in serv_addr;
socklen_t serv_len = sizeof(serv_addr);
char buffer[BUFFER_SIZE] = {0};
const char *message = "Hello from UDP client";
// 1. 创建 UDP Socket
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
// 3. 向服务器发送数据
sendto(sock_fd, message, strlen(message), 0, (struct sockaddr *)&serv_addr, serv_len);
printf("Message sent\n");
// 4. 接收服务器响应
int n = recvfrom(sock_fd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&serv_addr, &serv_len);
buffer[n] = '\0';
printf("Received from server: %s\n", buffer);
// 5. 关闭Socket
close(sock_fd);
return 0;
}
430

被折叠的 条评论
为什么被折叠?



