Linux下,write/read,recv/send, recvfrom/sendto的区别

先说概念和应用场景:read/wirte是通用的文件描述符操作;recv/send 通常应用于TCP;recvfrom/sendto通常应用于UDP。

1. read/write

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

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

write函数是将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量.。

read函数是从fd中读取内容.当读成功 时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误。 如果是ECONNREST表示网络连接出了问题。

 

2. recv/send

socket建立好了tcp连接之后,我们就可以把得到的fd当作文件描述符,此时可以使用read/write来操作。

在网络程序中,当我们向套接字文件描述符读写时有两可能,需要我们自己处理:
1) write的返回值大于0,表示写了部分或者是全部的数据. 这样我们用一个while循环来不停的写入,但是循环过程中的buf参数和nbyte参数得由我们来更新。也就是说,网络写函数是不负责将全部数据写完之后在返回的(read同)。
2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理。(read同)
如果错误为EINTR表示在写的时候出现了中断错误.
如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接)。

recv和send函数提供了第四个参数来控制读写操作,依次解决上述问题。
int recv(int sockfd,void *buf,int len,int flags);
int send(int sockfd,void *buf,int len,int flags);

前面的三个参数和read, write一样,第四个参数可以是0或者是以下的组合
______________________________________________________________
| MSG_DONTROUTE | 不查找表 |
| MSG_OOB | 接受或者发送带外数据 |
| MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 |
| MSG_WAITALL | 等待所有数据 |
|-------------------------------------------------------------------------------------------------------|

MSG_DONTROUTE:是 send函数使用的标志.这个标志告诉IP.目的主机在本地网络上面,没有必要查找表.这个标志一般用网络诊断和路由程序里面。
MSG_OOB:表示可以接收和发送带外的数据.关于带外数据我们以后会解释的.

MSG_PEEK:recv函数的使用标志, 表示只是从系统缓冲区中读取内容,而不清除系统缓冲区的内容.这样下次读的时候,仍然是一样的内容.一般在有多个进程读写数据时可以使用这个标志.

MSG_WAITALL 是recv函数的使用标志,表示等到所有的信息到达时才返回.使用这个标志的时候recv回一直阻塞,直到指定的条件满足,或者是发生了错误. 1)当读到了指定的字节时,函数正常返回.返回值等于len 2)当读到了文件的结尾时,函数正常返回.返回值小于len 3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno)

MSG_NOSIGNAL is a flag used by send() in some implementations of the Berkeley sockets API.

This flag requests that the implementation does not to send a SIGPIPE signal on errors on stream oriented sockets when the other end breaks the connection. The EPIPE error is still returned as normal.

Though it is in some Berkely sockets APIs (notably Linux) it does not exist in what some refer to as the reference implementation, FreeBSD, which instead uses a socket option SO_NOSIGPIPE?. 对于服务器端,我们可以使用这个标志。目的是不让其发送SIG_PIPE信号,导致程序退出。

如果flags为0,则和read,write一样的操作.还有其它的几个选项,不过我们实际上用的很少,可以查看 Linux Programmer's Manual得到详细解释。

 

3. recvfrom/sendto

利用数据报方式进行数据传输,在无连接的数据报socket方式下(UDP),由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto()函数原型为: 

int recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from, int *fromlen);

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

• buf,指向容纳接收信息的缓冲区的指针
• len,缓冲区的大小
• flags,接收标志
• from,指明接收数据的来源
• fromlen, 函数返回实际接收的字节数,返回-1表示出错
• to,指明发送数据的目的地
• tolen, 函数返回已发送的字节数,返回-1表示出错


注:recvfrom和sendto都是阻塞

 

 

 

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你提到了使用C语言编写服务器的步骤,这是一个不错的指南,下面我会逐一解释每个步骤的作用。 1. `socket()` 创建流式套接字 `socket()` 函数是创建套接字的第一步。套接字是网络编程中最基本的概念,它用于在网络上进行通信。在此过程中,我们需要指定协议簇、套接字类型和协议类型。其中,协议簇通常选择 AF_INET(IPv4),套接字类型选择 SOCK_STREAM(流式套接字),协议类型通常默认为 0(自动选择协议)。 ```c int socket(int domain, int type, int protocol); ``` 2. `bind()` 绑定自己的地址信息 `bind()` 函数用于将套接字和本地 IP 地址及端口号绑定起来。在此过程中,我们需要指定一个本地 IP 地址和一个端口号。如果绑定成功,则可以通过该 IP 地址和端口号访问该套接字。 ```c int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); ``` 3. `listen()` 设置成被动监听状态 `listen()` 函数用于将套接字设置为被动监听状态,以等待客户端的连接请求。在此过程中,我们需要指定队列的最大长度。如果队列已满,则新的连接请求将被拒绝。 ```c int listen(int sockfd, int backlog); ``` 4. `accept()` 等待并接受连接请求 `accept()` 函数用于等待客户端的连接请求,并返回一个新的套接字。在此过程中,我们需要指定一个指向用于存储客户端地址信息的结构体地址和结构体长度。如果该函数执行成功,则表示已经成功建立了一条连接。 ```c int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); ``` 5. `recv()`/`recvfrom()` 接受数据信息 `recv()` 或 `recvfrom()` 函数用于接收从客户端发送过来的数据信息。在此过程中,我们需要指定接收缓冲区的地址和大小。如果成功接收到数据,则返回接收到的字节数。 ```c ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); ``` 6. `send()`/`sendto()` 发送数据信息 `send()` 或 `sendto()` 函数用于向客户端发送数据信息。在此过程中,我们需要指定发送缓冲区的地址和大小。如果成功发送数据,则返回发送的字节数。 ```c ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); ``` 7. `close()` 关闭套接字 `close()` 函数用于关闭套接字,释放资源。在此过程中,我们需要传入套接字的文件描述符。 ```c int close(int sockfd); ``` 这些函数是使用 C 语言编写服务器时经常使用的函数。使用它们可以建立一个简单的服务器,实现基本的通信功能。当然,在实际应用中,还需要更多的功能和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值