- 网络编程基础概念
- IP地址:是互联网协议地址,用于在网络中唯一标识一台设备。在IPv4中,地址是32位的二进制数,通常以点分十进制表示,如
192.168.1.1
。IPv6是128位的地址,用于提供更多的地址空间,格式更复杂。 - 端口号:用于标识一台主机上的不同应用程序或服务。端口号范围是0 - 65535,其中0 - 1023被系统保留用于一些知名的服务,如HTTP(80)、HTTPS(443)、SSH(22)等。应用程序可以使用其他端口号来提供服务或进行通信。
- 协议:网络协议规定了网络通信的规则和格式。常见的协议有TCP(传输控制协议)和UDP(用户数据报协议)。
- TCP:是一种面向连接的、可靠的传输协议。它通过三次握手建立连接,在数据传输过程中会进行流量控制、拥塞控制和差错校验等,保证数据的可靠传输。适用于对数据准确性要求较高的场景,如文件传输、网页浏览等。
- UDP:是一种无连接的、不可靠的传输协议。它不建立连接,数据发送方只管发送数据,接收方只管接收数据,不保证数据一定能到达,也不保证数据的顺序。但UDP具有传输速度快、开销小的特点,适用于对实时性要求较高,对数据准确性要求相对较低的场景,如视频直播、实时游戏等。
- 套接字(Socket)编程基础
- 套接字的概念:在Linux网络编程中,套接字是一种通信机制,它提供了应用程序与网络协议栈之间的接口,使得应用程序可以通过网络进行通信。可以把套接字看作是通信的端点,就像电话的插座一样,应用程序通过它来发送和接收数据。
- 套接字的类型:
- 流式套接字(SOCK_STREAM):基于TCP协议,提供面向连接的、可靠的字节流服务。
- 数据报套接字(SOCK_DGRAM):基于UDP协议,提供无连接的、不可靠的数据报服务。
- 基于TCP的网络编程
- 服务器端编程步骤:
- 创建套接字:使用
socket
函数创建一个套接字。函数原型为int socket(int domain, int type, int protocol);
,其中domain
指定协议族(如AF_INET
表示IPv4),type
指定套接字类型(如SOCK_STREAM
表示TCP套接字),protocol
通常设为0,表示使用默认协议。例如:int sockfd = socket(AF_INET, SOCK_STREAM, 0);
。 - 绑定地址和端口:使用
bind
函数将套接字绑定到一个本地地址和端口。函数原型为int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
,其中sockfd
是套接字描述符,addr
是指向sockaddr
结构体(对于IPv4通常使用sockaddr_in
)的指针,包含IP地址和端口号信息,addrlen
是结构体的长度。例如:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
- **监听端口**:使用`listen`函数让套接字进入监听状态,等待客户端连接。函数原型为`int listen(int sockfd, int backlog);`,其中`sockfd`是套接字描述符,`backlog`表示等待连接队列的最大长度。例如:`listen(sockfd, 5);`。
- **接受客户端连接**:使用`accept`函数接受客户端连接,该函数会阻塞,直到有客户端连接。函数原型为`int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);`,它返回一个新的套接字描述符,用于与客户端进行通信,原套接字继续监听其他客户端连接。例如:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
- **与客户端通信**:使用`send`和`recv`函数在服务器端和客户端之间发送和接收数据。例如:
char buffer[1024];
recv(client_sockfd, buffer, sizeof(buffer), 0);
send(client_sockfd, "服务器响应", strlen("服务器响应"), 0);
- **关闭套接字**:使用`close`函数关闭套接字,释放资源。例如:`close(client_sockfd); close(sockfd);`。
- 客户端编程步骤:
- 创建套接字:同服务器端,使用
socket
函数创建一个套接字。例如:int sockfd = socket(AF_INET, SOCK_STREAM, 0);
。 - 连接服务器:使用
connect
函数连接到服务器。函数原型为int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
,其中sockfd
是套接字描述符,addr
是指向包含服务器地址和端口号的sockaddr
结构体的指针,addrlen
是结构体长度。例如:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
- **与服务器通信**:使用`send`和`recv`函数发送和接收数据,与服务器端类似。
- **关闭套接字**:使用`close`函数关闭套接字。
- 基于UDP的网络编程
- 服务器端编程步骤:
- 创建套接字:使用
socket
函数创建一个UDP套接字。例如:int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
。 - 绑定地址和端口:使用
bind
函数将套接字绑定到本地地址和端口,与TCP服务器端类似。 - 接收和发送数据:使用
recvfrom
和sendto
函数接收和发送数据。recvfrom
函数原型为ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
,用于接收数据并获取发送方的地址。sendto
函数原型为ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
,用于向指定地址发送数据。例如:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[1024];
recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &client_len);
sendto(sockfd, "服务器响应", strlen("服务器响应"), 0, (struct sockaddr *)&client_addr, client_len);
- **关闭套接字**:使用`close`函数关闭套接字。
- 客户端编程步骤:
- 创建套接字:同服务器端,创建一个UDP套接字。
- 发送和接收数据:使用
sendto
和recvfrom
函数发送和接收数据,与服务器端类似,但不需要绑定地址和端口(系统会自动分配),或者可以绑定一个本地地址和端口用于接收服务器响应。 - 关闭套接字:使用
close
函数关闭套接字。
- 高级网络编程主题
- 非阻塞套接字和异步I/O:默认情况下,套接字操作是阻塞的,即函数(如
accept
、recv
等)会一直等待操作完成。非阻塞套接字可以让这些操作立即返回,通过轮询或使用异步I/O机制(如select
、poll
、epoll
等)来检查操作是否完成。epoll
是Linux特有的高性能I/O复用机制,相比select
和poll
,它在处理大量并发连接时效率更高。 - 多线程/多进程网络服务器:为了提高服务器的并发处理能力,可以使用多线程或多进程来处理客户端连接。在多线程网络服务器中,主线程负责监听客户端连接,当有连接时,创建一个新线程来处理与该客户端的通信。多进程网络服务器类似,但使用进程来处理通信,进程间通信可以通过管道、共享内存等方式实现。
- 网络安全相关编程:在网络编程中,安全是非常重要的。可以使用SSL/TLS协议来加密网络通信,防止数据被窃取或篡改。在Linux中,
OpenSSL
库是常用的加密库,通过它可以实现安全的网络连接,如在HTTP基础上实现HTTPS。