一、 Socket 概述
Socket 是一种用于在不同进程间进行网络通信的机制,也是 Linux 下网络编程的基础,也就是说在 Linux 下进行网络通信主要就是使用 Socket。
其中 Socket 可以描述成是文件描述符,它是一个整数,就像文件描述符一样可以使用 read、write、close 等函数对它进行操作。Socket 可以分为两种类型:流式 Socket 和数据报式 Socket。
二、网络编程基础 API
下面先列举一些 Network编程基础 API:
//创建 Socket int socket(int domain, int type, int protocol); //命名 Socket int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); //将未连接的 Socket 转换为连接的 Socket int listen(int sockfd, int backlog); //向 Socket 发送数据 ssize_t send(int sockfd, const void *buf, size_t len, int flags); //从 Socket 接收数据 ssize_t recv(int sockfd, void *buf, size_t len, int flags); //建立连接请求的服务端 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //发起连接请求的客户端 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); // 关闭 Socket int close(int sockfd);
三、流式 Socket
流式 Socket 是由 TCP 协议提供服务的,主要用于可靠的、有序的、基于连接的数据传输,特点如下:
1.面向连接;
2.提供可靠的数据传输;
3.通过三次握手连接,确保连接的建立;
4.数据是按顺序传输的,不存在数据丢失、重复等问题。
3.1 服务端实现
// 创建 Socket int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); // 命名 Socket struct sockaddr_in server_address; server_address.sin_family = AF_INET; // 地址族 server_address.sin_port = htons(12345); // 端口号 server_address.sin_addr.s_addr = htonl(INADDR_ANY); // IP 地址,INADDR_ANY 表示可以接收任何地址 bind(server_sockfd, (struct sockaddr *)&server_address, sizeof(server_address)); // 将未连接的 Socket 转换为连接的 Socket listen(server_sockfd, 5); // 服务端等待客户端的连接请求 int client_sockfd; struct sockaddr_in client_address; socklen_t client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); // 向客户端发送数据 char message[] = "Hello, client!"; write(client_sockfd, message, sizeof(message)); // 关闭 Socket close(client_sockfd); close(server_sockfd);
3.2 客户端实现
// 创建 Socket int client_sockfd = socket(AF_INET, SOCK_STREAM, 0); // 向服务端发起连接请求 struct sockaddr_in server_address; server_address.sin_family = AF_INET; // 地址族 server_address.sin_port = htons(12345); // 端口号 server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(client_sockfd, (struct sockaddr*)&server_address, sizeof(server_address)); // 从服务端接收数据 char message[1024]; read(client_sockfd, message, sizeof(message)); printf("Message from server: %s\n", message); // 关闭 Socket close(client_sockfd);
四、数据报式 Socket
数据报式 Socket 是由 UDP 协议提供服务的,主要用于无连接、不可靠、允许数据失去和重复等问题的数据传输,特点如下:
1.无连接;
2.数据传输不可靠;
3.没有三次握手连接,也无需维护连接状态;
4.数据传输可能丢失、重复等问题。
4.1 服务端实现
// 创建 Socket int server_sockfd; server_sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 命名 Socket struct sockaddr_in server_address; server_address.sin_family = AF_INET; // 地址族 server_address.sin_port = htons(12345); // 端口号 server_address.sin_addr.s_addr = htonl(INADDR_ANY); // IP 地址,INADDR_ANY 表示可以接收任何地址 bind(server_sockfd, (struct sockaddr*)&server_address, sizeof(server_address)); // 接收客户端发送的数据 char message[1024]; struct sockaddr_in client_address; socklen_t client_len = sizeof(client_address); recvfrom(server_sockfd, message, sizeof(message), 0, (struct sockaddr*)&client_address, &client_len); printf("message from client: %s\n", message); // 向客户端发送数据 char reply[] = "Hello, client!"; sendto(server_sockfd, reply, sizeof(reply), 0, (struct sockaddr *)&client_address, client_len); // 关闭 Socket close(server_sockfd);
4.2 客户端实现
// 创建 Socket int client_sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 向服务端发送数据 char message[] = "Hello, server!"; struct sockaddr_in server_address; server_address.sin_family = AF_INET; // 地址族 server_address.sin_port = htons(12345); // 端口号 server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); sendto(client_sockfd, message, sizeof(message), 0, (struct sockaddr *)&server_address, sizeof(server_address)); // 接收服务端发送的数据 char reply[1024]; struct sockaddr_in reply_address; socklen_t reply_len = sizeof(reply_address); recvfrom(client_sockfd, reply, sizeof(reply), 0, (struct sockaddr *)&reply_address, &reply_len); printf("reply from server: %s\n", reply); // 关闭 Socket close(client_sockfd);
五、总结
Linux Socket 编程是进行网络通信的基础,对于理解网络通信原理、网络编程都非常重要。本文主要介绍了流式 Socket 和数据报式 Socket 的创建、命名、通信等基本操作,通过代码示例的方式进行详细阐述。