在Linux系统中,套接字(Socket)是一种用于实现网络通信的技术,套接字允许在同一台计算机上的不同进程或不同计算机之间进行数据传输,本文将详细介绍Linux下套接字的基本概念、使用方法以及相关技术。
一、套接字基本概念
1. 地址(Address):套接字地址是一个四元组,包括协议族、套接字类型、套接字编号和IP地址,对于TCP/IP协议族的UDP套接字,地址格式为`(AF_INET, SOCK_DGRAM, 0, IP_ADDR)`,其中`AF_INET`表示IPv4地址,`SOCK_DGRAM`表示UDP协议,`0`表示随机分配的端口号,`IP_ADDR`表示IP地址。
2. 端口(Port):端口是应用程序用来进行通信的逻辑通道,每个应用程序都有一个唯一的端口号,用于标识该应用程序,通常情况下,操作系统会自动分配一个可用的端口号给应用程序。
3. 缓冲区(Buffer):缓冲区是用于存储发送和接收数据的临时区域,当应用程序需要发送或接收数据时,首先将数据写入缓冲区,然后通过套接字将缓冲区的数据发送到目标地址。
二、套接字创建与关闭
1. 创建套接字:使用`socket()`函数创建一个新的套接字,函数原型如下:
```c
include
include
int socket(int domain, int type, int protocol);
参数说明: - `domain`:指定套接字使用的协议族,如`AF_INET`表示IPv4协议族,`AF_INET6`表示IPv6协议族。 - `type`:指定套接字使用的类型,如`SOCK_STREAM`表示面向连接的流式套接字,`SOCK_DGRAM`表示无连接的数据报套接字。 - `protocol`:指定使用的协议,通常设置为0表示使用默认协议。 2. 绑定套接字:使用`bind()`函数将套接字与特定的地址关联起来。函数原型如下: ```c #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数说明:
- `sockfd`:已创建的套接字描述符。
- `addr`:指向要绑定的地址结构的指针。
- `addrlen`:`addr`指向的地址结构的大小。
3. 监听套接字:使用`listen()`函数使套接字进入监听状态,等待客户端发起连接请求,函数原型如下:
int listen(int sockfd, int backlog);
参数说明: - `sockfd`:已创建的套接字描述符。 - `backlog`:允许的最大挂起连接数。 4. 关闭套接字:使用`close()`函数关闭套接字。函数原型如下: ```c #include <unistd.h> int close(int fd);
- `fd`:要关闭的套接字描述符。
三、套接字通信示例
下面是一个简单的TCP服务器和客户端的示例代码:
服务器端代码:
include
include
include
include
include
include
define BUF_SIZE 1024
void error_handling(char *message);
int main(int argc, char *argv[]) {
int serv_sock, clnt_sock; // 服务器端socket描述符和客户端socket描述符
struct sockaddr_in serv_addr, clnt_addr; // 服务器端和客户端地址信息结构体变量(IP地址+端口号)和服务端地址信息结构体变量相同只是端口号不同而已!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!) (注解) "
"; "
" "
" "
"; ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解") ("注解"); ("注解") ("注解") ("注解") ("注解") ("注解"); uint16_t port = htons(8888); // 将端口号从主机字节序转换为网络字节序(注意这里是16位的无符号整型变量) (注意这里也是16位的无符号整型变量) char buffer[BUF_SIZE]; // 定义接收数据的缓冲区struct sockaddr_in serv_addr; // 定义服务端地址结构体变量serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 创建socket描述符 if (serv_sock == -1) error_handling("socket() error"); // 如果创建失败则调用错误处理函数 memset(&serv_addr, 0, sizeof(serv_addr)); // 将服务端地址信息结构体变量清零 inet_pton(PF_INET, "127.0.0.1", &serv_addr.sin_addr); // 将字符串形式的IP地址转换成二进制形式并赋值给服务端地址信息结构体变量 sin_port = htons(port); // 将端口号从主机字节序转换为网络字节序并赋值给服务端地址信息结构体变量 if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) error_handling("bind() error"); // 如果绑定失败则调用错误处理函数 if (listen(serv_sock, 5) == -1) error_handling("listen() error"); // 如果监听失败则调用错误处理函数 while (1) { clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, (socklen_t *)&sizeof(clnt_addr)); // 建立客户端连接 if (clnt_sock == -1) error_handling("accept() error"); // 如果建立连接失败则调用错误处理函数 memset(buffer, 0, sizeof(buffer)); // 将缓冲区清零 send(clnt_sock, buffer, sizeof(buffer), 0); // 将数据发送给客户端 printf("Received message from client: %s
", buffer); // 从客户端接收消息并打印 read(clnt_sock, buffer, sizeof(buffer)); // 从客户端接收数据并保存到缓冲区中 close(clnt_sock); // 关闭客户端连接 close(serv_sock); // 关闭服务器端socket描述符 return 0; // 返回0表示程序正常结束;} void error_handling(char *message) { fputs(message, stderr); fputc('
', stderr); exit(1);} ```
原创文章,作者:K-seo,如若转载,请注明出处:https://www.kdun.cn/ask/55387.html