本帖最后由 feifeiz 于 2023-10-4 00:51 编辑
1. Socket 简介
套接字(socket)是 Linux 下的一种进程间通信机制(socket IPC),使用 socket IPC 可以使得在不同主机上的应用程序之间进行通信(**通信),当然也可以是同一台主机上 的不同应用程序。socket IPC 通常使用客户端<--->服务器这种模式完成通信,多个客户端可以同时连接到服务器中,与服务器之间完成数据交互。 内核向应用层提供了 socket 接口,调用 socket 接口开发自己的应用程序即可!socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口。socket 其实就是一个门面模式,它把复杂的 TCP/IP 协议隐藏在 socket 接口后面,对用户来说,一组简单的 接口就是全部,让 socket 去组织数据,以符合指定的协议。当前**中的主流程序设计都是使用 socket 进行编程的,因为它简单易用,它还是一个标准(BSD socket),能在不同**很方便移植,比如你的一个应用程序是基于 socket 接口编写的,那么它可以移植到任何实现 BSD socket 标准的**。
2. Socket 接口
1. **创建套接字 (`socket()`)**: - 函数原型:`int socket(int domain, inttype, int protocol);` - 用途:创建一个新的套接字,返回一个套接字描述符。 - 参数: - `domain`:套接字的协议族,通常是 `AF_INET`(IPv4)或 `AF_INET6`(IPv6)。 - `type`:套接字的类型,通常是 `SOCK_STREAM`(流套接字)或 `SOCK_DGRAM`(数据报套接字)。 - `protocol`:套接字的协议,通常可以设置为0,由系统自动选择合适的协议。 - 示例: intserver_socket = socket(AF_INET, SOCK_STREAM, 0);
2. **绑定套接字到地址和端口 (`bind()`)**: - 函数原型:`int bind(int sockfd, conststruct sockaddr *addr, socklen_t addrlen);` - 用途:将套接字绑定到特定的IP地址和端口号。 - 参数: - `sockfd`:套接字描述符。 - `addr`:一个 `struct sockaddr` 结构,指定了要绑定的地址和端口。 - `addrlen`:`addr` 结构的长度。 - 示例: structsockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); // 使用8080端口 server_addr.sin_addr.s_addr = INADDR_ANY; bind(server_socket, (struct sockaddr*)&server_addr,sizeof(server_addr));
3. **启动服务器监听 (`listen()`)**: - 函数原型:`int listen(int sockfd, intbacklog);` - 用途:仅用于服务器套接字,用于启动监听模式,以等待客户端连接请求。 - 参数: - `sockfd`:服务器套接字描述符。 - `backlog`:等待连接队列的最大长度,指定同时能处理多少个等待连接的客户端。 - 示例: listen(server_socket, 5); // 允许最多5个等待连接的客户端
4. **接受客户端连接请求 (`accept()`)**: - 函数原型:`int accept(int sockfd, structsockaddr *addr, socklen_t *addrlen);` - 用途:仅用于服务器套接字,用于接受客户端的连接请求,返回一个新的套接字描述符,用于与客户端通信。 - 参数: - `sockfd`:服务器套接字描述符。 - `addr`:一个 `struct sockaddr` 结构,用于存储客户端的地址信息。 - `addrlen`:`addr` 结构的长度。 - 示例: intclient_socket; structsockaddr_in client_addr; socklen_tclient_addr_len = sizeof(client_addr); client_socket =accept(server_socket, (struct sockaddr*)&client_addr,&client_addr_len);
5. **客户端连接服务器 (`connect()`)**: - 函数原型:`int connect(int sockfd, conststruct sockaddr *addr, socklen_t addrlen);` - 用途:用于客户端套接字,用于连接到服务器的指定地址和端口。 - 参数: - `sockfd`:客户端套接字描述符。 - `addr`:一个 `struct sockaddr` 结构,指定了服务器的地址和端口。 - `addrlen`:`addr` 结构的长度。 - 示例: structsockaddr_in server_addr; server_addr.sin_family = AF_INET; server_addr.sin_port= htons(8080); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); connect(client_socket, (struct sockaddr*)&server_addr,sizeof(server_addr));
6. **发送数据 (`send()`)**: - 函数原型:`ssize_t send(int sockfd, constvoid *buf, size_t len, int flags);` - 用途:将数据从套接字发送到远程端点。 - 参数: - `sockfd`:套接字描述符。 - `buf`:要发送的数据的缓冲区。 - `len`:要发送的数据的长度。 - `flags`:标志位,通常设置为0。 - 示例: char message[] ="Hello, server!"; send(client_socket, message, strlen(message), 0);
7. **接收数据 (`recv()`)**: - 函数原型:`ssize_t recv(int sockfd, void*buf, size_t len, int flags);` - 用途:从套接字接收数据。 - 参数: - `sockfd`:套接字描述符。 - `buf`:用于存储接收数据的缓冲区。 - `len`:缓冲区的长度。 - `flags`:标志位,通常设置为0。 - 示例: charbuffer[1024]; intbytes_received = recv(client_socket, buffer, sizeof(buffer), 0);
8. **关闭套接字 (`close()`)**: - 函数原型:`int close(int sockfd);` - 用途:关闭套接字连接或释放套接字资源。 - 参数: - `sockfd`:套接字描述符。 - 示例: close(client_socket); close(server_socket);
3.应用编程测试
服务器端代码: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h>
int main() { int server_socket, client_socket; struct sockaddr_in server_addr,client_addr; char buffer[1024];
// 创建服务器套接字 server_socket = socket(AF_INET,SOCK_STREAM, 0); if (server_socket == -1) { perror("Socket creationfailed"); exit(1); }
// 设置服务器地址和端口 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); // 使用8080端口 server_addr.sin_addr.s_addr = INADDR_ANY;
// 绑定套接字到地址和端口 if (bind(server_socket, (structsockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("Binding failed"); exit(1); }
// 启动服务器监听 if (listen(server_socket, 5) == -1) { perror("Listening failed"); exit(1); } printf("Server listening on port8080...\n");
socklen_t client_addr_len =sizeof(client_addr);
// 接受客户端连接请求 client_socket = accept(server_socket,(struct sockaddr*)&client_addr, &client_addr_len); if (client_socket == -1) { perror("Accepting connectionfailed"); exit(1); }
printf("Client connected.\n");
// 接收客户端数据 int bytes_received = recv(client_socket,buffer, sizeof(buffer), 0); if (bytes_received == -1) { perror("Receiving datafailed"); exit(1); } buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received from client:%s\n", buffer);
// 发送数据到客户端 char message[] = "Hello,client!"; int bytes_sent = send(client_socket,message, strlen(message), 0); if (bytes_sent == -1) { perror("Sending datafailed"); exit(1); }
// 关闭套接字连接 close(client_socket); close(server_socket);
return 0; }
客户端代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<arpa/inet.h>
int main() { int client_socket; struct sockaddr_in server_addr; char buffer[1024];
// 创建套接字 client_socket = socket(AF_INET,SOCK_STREAM, 0); if (client_socket == -1) { perror("Socket creationfailed"); exit(1); }
// 连接到服务器 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(8080); server_addr.sin_addr.s_addr = inet_addr("192.168.1.13"); if (connect(client_socket, (structsockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("Connection failed"); exit(1); }
// 发送数据到服务器 char message[] = "Hello,server!"; int bytes_sent = send(client_socket, message,strlen(message), 0); if (bytes_sent == -1) { perror("Sending datafailed"); exit(1); }
// 接收服务器数据 int bytes_received = recv(client_socket,buffer, sizeof(buffer), 0); if (bytes_received == -1) { perror("Receiving datafailed"); exit(1); } buffer[bytes_received] = '\0'; // 添加字符串结束符
printf("Received from server:%s\n", buffer);
// 关闭套接字连接 close(client_socket);
return 0; }
编译代码:
输入以下命令编译代码: 电脑运行客户端,开发板运行服务器端: arm-linux-gnueabihf-gcc-o server server.c gcc client.c -oclient
将编译的可执行文件传入开发板中,运行服务器端:
|