Linux系列-send recv与read write以及sendto的区别

在网络编程中,`send`、`recv`、`read`、`write`都是常用的系统调用或函数,用于在套接字上发送或接收数据。虽然它们的功能有相似之处,但使用场景和细节上有所不同。以下是对它们的详细对比:

 

1. send和 recv

 

适用场景:专门用于套接字(Socket)上的数据传输。通常用于网络编程(如TCP/UDP通信)。

协议支持: 主要用于面向连接(TCP)和无连接(UDP)通信的协议。

 

 send`函数

 

- 作用: 通过套接字向连接的另一端发送数据。

- 函数原型:

  ```c

  ssize_t send(int sockfd, const void *buf, size_t len, int flags);

  ```

  - `sockfd`: 套接字描述符。

  - `buf`: 需要发送的数据缓冲区。

  - `len`: 缓冲区中数据的长度。

  - `flags`: 可以指定一些标志(如`MSG_DONTWAIT`用于非阻塞发送等)。

 

- 特点: 可以通过`flags`标志来控制发送行为。它仅用于套接字,不能用于其他文件描述符。适合在有特殊发送需求的场景下使用。

 

 `recv` 函数

 

- 作用: 从套接字接收数据。

- 函数原型:

  ```c

  ssize_t recv(int sockfd, void *buf, size_t len, int flags);

  ```

  - `sockfd`: 套接字描述符。

  - `buf`: 接收数据的缓冲区。

  - `len`: 缓冲区的大小。

  - `flags`: 可以指定一些标志(如`MSG_PEEK`用于查看数据而不移除它,`MSG_WAITALL`等待所有数据到达等)。

 

- 特点: 通过`flags`可以控制接收行为,通常用于网络通信的接收操作。

 

2. `read` 和 `write`

 

- 适用场景: 通用的I/O操作,可以用于文件、管道、套接字等不同类型的文件描述符。

- 协议支持: 不局限于网络编程,可以用于各种文件系统的读写操作。

 

 `write` 函数

 

- 作用: 向文件描述符(包括套接字)写入数据。

- 函数原型:

  ```c

  ssize_t write(int fd, const void *buf, size_t count);

  ```

  - `fd`: 文件描述符。

  - `buf`: 需要写入的数据缓冲区。

  - `count`: 缓冲区中的数据长度。

 

- 特点: 是一个通用的I/O操作函数,可以用于任何类型的文件描述符,包括文件、管道、设备、套接字等。

 

`read` 函数

 

- 作用: 从文件描述符(包括套接字)读取数据。

- 函数原型:

  ```c

  ssize_t read(int fd, void *buf, size_t count);

  ```

  - `fd`: 文件描述符。

  - `buf`: 用于存储读取数据的缓冲区。

  - `count`: 要读取的数据长度。

 

- **特点**: 和`write`一样,它是一个通用的I/O操作函数。可以在套接字中使用,也可以用于文件系统中的读操作。

 

**主要区别**

 

1. 应用场景不同:

   - `send`和`recv`是专门为网络编程设计的,用于套接字通信。

   - `read`和`write`是通用的I/O函数,可以用于文件、管道、设备以及网络套接字等。

   

2. 功能控制不同:

   - `send`和`recv`具有更多针对网络通信的特殊功能,可以通过`flags`参数来设置不同的发送或接收模式,如非阻塞、查看而不移除数据等。

   - `read`和`write`没有这些网络相关的额外功能,它们只执行最基本的数据传输。

 

3. 协议支持:

   - `send`和`recv`主要用于支持TCP/UDP等协议的套接字通信。

   - `read`和`write`不仅可以用于网络套接字,也可以用于文件系统的操作。

 

总结:

- 如果进行网络编程,且需要控制发送或接收的行为(如使用特殊标志),通常会选择`send`和`recv`。

- 如果不需要对网络数据传输进行特殊控制,或者需要一个通用的I/O操作,通常使用`read`和`write`。

 

另外补充下send与sendto的区别;

在网络编程中,`send`和`sendto`函数都用于发送数据,但它们在使用场景上有所不同,尤其是在面向连接(TCP)和无连接(UDP)协议中。

1. send函数

- 适用协议: 面向连接的协议(如TCP)。

- 参数说明: 

  - `send`函数只需要提供已建立连接的套接字(socket)描述符和要发送的数据。

  - 它依赖于已建立的连接,调用时不需要指定目标地址,因为连接建立时已绑定了目标地址。

  

- 常用函数签名:

  ```c

  ssize_t send(int sockfd, const void *buf, size_t len, int flags);

  ```

  - `sockfd`: 套接字描述符,表示已建立连接的套接字。

  - `buf`: 要发送的数据缓冲区。

  - `len`: 要发送的数据长度。

  - `flags`: 发送的标志位(如是否带有特殊控制,如`MSG_DONTWAIT`等)。

 

- 使用场景: 通常在TCP协议中使用,适用于已建立的连接。只需要传递数据,不需要每次发送都指定目标地址。

 

- **示例**:

  ```c

  int sockfd = socket(AF_INET, SOCK_STREAM, 0);

  connect(sockfd, ...); // 先建立连接

  send(sockfd, "Hello", 5, 0); // 发送数据

  ```

 

2. sendto函数

- 适用协议: 无连接的协议(如UDP),但也可以用于面向连接的协议(TCP)。

- 参数说明: 

  - `sendto`可以用于发送数据到特定的目标地址,不需要建立连接。

  - 除了指定数据和套接字之外,`sendto`还需要提供目标地址信息,因此适合于无连接的协议。

  

- 常用函数签名:

  ```c

  ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

                 const struct sockaddr *dest_addr, socklen_t addrlen);

  ```

  - `sockfd`: 套接字描述符,可以是无连接的UDP套接字。

  - `buf`: 要发送的数据缓冲区。

  - `len`: 要发送的数据长度。

  - `flags`: 发送的标志位。

  - `dest_addr`: 目标地址结构体,表示目标主机的地址和端口。

  - `addrlen`: 目标地址的长度。

 

- 使用场景: 通常用于UDP协议,适合无连接的网络通信,每次发送都需要指定目标地址。对于TCP,可以在连接建立后使用`sendto`发送到特定的地址,不过这种用法较为少见。

 

- 示例:

  ```c

  int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // UDP套接字

  struct sockaddr_in dest_addr;

  dest_addr.sin_family = AF_INET;

  dest_addr.sin_port = htons(8080);

  dest_addr.sin_addr.s_addr = inet_addr("192.168.1.1");

  sendto(sockfd, "Hello", 5, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));

  ```

总结

- `send`: 通常用于TCP,在连接建立后只需要发送数据,不需要每次指定目标地址。

- `sendto`: 通常用于UDP,无需建立连接,每次发送都需要指定目标地址,可以在无连接的场景中使用。

 

如果你在进行UDP编程,那么使用`sendto`更为合适,因为它可以灵活指定目标地址。而在TCP编程中,`send`通常更简便,因为TCP会在连接建立时绑定地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值