此文章为本人学习笔记,若有错误求指正,自学推荐书籍《Linux/UNIX系统编程手册》,需要该书籍pdf文档可无偿分享。
Linux网络编程是指在Linux操作系统上开发网络应用程序的过程。网络编程的核心是Socket编程,Socket是操作系统提供的用于网络通信的接口。
网络通信通常基于OSI模型,该模型分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。在实际编程中,我们主要关注传输层及以上的内容。
五层体系的协议结构是综合了 OSI 和 TCP/IP 优点的一种协议,包括应用层、传输层、网络层、数据链路层和物理层。其中应用层对应 OSI 的上三层,下四层和 OSI 相同。五层协议的体系结构只是为介绍网络原理而设计的,实际应用还是 TCP/IP 四层体系结构。
TCP/IP协议是互联网的核心协议,其中传输层协议TCP和UDP是网络编程中最常用的协议。
提供可靠的、面向连接的服务。常用于文件传输、邮件传输等对数据完整性要求高的场景。
TCP建立连接的三次握手:
TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
TCP断开连接的四次握手:
TCP:服务端和客户端的通信流程:
提供无连接的、不可靠的数据报服务。适用于对速度要求高,但对数据完整性要求不高的场景,如视频流、语音通信等。
Socket是网络编程的核心接口,用于建立和管理网络连接。
函数概述
socket()函数用于创建一个新的套接字,并返回套接字的文件描述符。如果套接字创建失败,函数将返回-1。
函数原型
int socket(int domain, int type, int protocol);
示例代码
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
函数概述
bind()函数将套接字与特定的IP地址和端口绑定,使其能够接收发送到该地址和端口的数据。
函数原型
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
示例代码
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
if (bind(sockfd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
函数概述
listen()函数将套接字设置为监听模式,准备接收来自客户端的连接请求。
函数原型
int listen(int sockfd, int backlog);
示例代码
if (listen(sockfd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
函数概述
accept()函数从监听套接字的连接队列中取出第一个连接请求,生成一个新的套接字用于与客户端通信。
函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
示例代码
int new_socket;
struct sockaddr_in client_address;
socklen_t addrlen = sizeof(client_address);
new_socket = accept(sockfd, (struct sockaddr *)&client_address, &addrlen);
if (new_socket < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
函数概述
connect()函数用于客户端与服务器建立连接,向指定的服务器地址和端口发送连接请求。
函数原型
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
5.3 示例代码
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("Invalid address/Address not supported");
exit(EXIT_FAILURE);
}
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Connection Failed");
exit(EXIT_FAILURE);
}
函数概述
send():将数据发送到已连接的套接字。
recv():从已连接的套接字接收数据。
函数原型
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
6.3 示例代码
char *message = "Hello, Server";
send(sockfd, message, strlen(message), 0);
char buffer[1024] = {0};
recv(sockfd, buffer, sizeof(buffer), 0);
printf("Message from server: %s\n", buffer);
函数概述
函数原型
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
示例代码
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;
char *message = "Hello, UDP Server";
sendto(sockfd, message, strlen(message), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
char buffer[1024] = {0};
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addr_len);
printf("Message from server: %s\n", buffer);
以下是一个简单的TCP服务器和客户端的实现。
TCP服务器
#include
#include
#include
#include
#include
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
if ((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(8080);
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);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
read(new_socket, buffer, 1024);
printf("Message: %s\n", buffer);
close(new_socket);
close(server_fd);
return 0;
}
TCP客户端
#include
#include
#include
#include
#include
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
printf("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
printf("Hello message sent\n");
read(sock, buffer, 1024);
printf("Message: %s\n", buffer);
close(sock);
return 0;
}