socket中write,read,send,recv函数

建立好了TCP连接之后,我们就可以把得到的套接字当做文件描述符来使用,基于流式数据操作的四大基本函数:

write函数

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

write函数将buf中的nbytes字节内容写入到文件描述符中,成功返回写入的字节数,失败返回-1,并设置errno变量。在网络程序中,当我们向套接字文件描述符写入数据有两种情况:
1、write的返回值大于0,表示写了部分数据或者是全部的数据,这样用一个while循环不断的写入数据,但是循环过程中的buf参数和nbytes参数是我们自己来更新的,也就是说,网络编程中写函数是不负责将全部数据写完之后再返回的,说不定中途就返回了!
2、返回值小于0,此时出错了,需要根据错误类型进行相应的处理。
如果错误是EINTR,表示在写的时候出现了中断错误,如果是EPIPE表示网络连接出现了问题。

read函数

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

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

对付上述可能出现的错误情况:

重写write:

//传入sockfd,buffer,长度
int my_write(int fd,const void *buffer,int length)
{
    int bytes_left;

    int write_bytes;

    char *ptr = buffer;

    bytes_left = length;

    while(bytes_left > 0)
    {
        //开始发送
        write_bytes = write(fd,ptr,bytes_left);
        if(write_bytes <= 0)//出错
        {
            if(errno == EINTR)//中断错误,继续发送
            {
                write_bytes = 0;
            }
            else
            {
                return -1;
            }
        }
        bytes_left -= write_bytes;
        ptr += write_bytes;/*从剩下的地方继续发送*/
    }
    return 0;
}

重写read:

int my_read(int fd,void *buff,int length)
{
    int bytes_left;

    int bytes_read;

    char *ptr;

    bytes_left = length;

    while(bytes_left > 0)
    {
        bytes_read = read(fd,ptr,bytes_left);

        if(bytes_read < 0)
        {
            if(errno == EINTR)
            {
                bytes_read = 0;
            }
            else
            {
                return -1;
            }
        }
        else if(bytes_read == 0)// 读取完毕
            break;

        bytes_left -= bytes_read;
        ptr += bytes_read;
    }
    return (length-bytes_left);//返回成功读取到的字节数
}

有了上面两个函数我们就可以向客户端或者服务器,进行数据传输了,并且可以处理一些基本的错误情况。

recv函数和send函数,用于TCP流数据读写的系统调用:

#include<sys/types.h>
#include<sys/socket.h>

ssize_t send(int sockfd,const void *buf,size_t len,int flags);
ssize_t recv(int sockfd,void *buf,size_t len,int flags);
send函数往sockfd上写入数据,buf和len参数分别表示写缓冲区的位置和大小。send成功时返回实际写入的数据的长度,失败返回-1,并设置errno.
recv读取sockfd上的数据,buf和len分别指定读缓冲区的位置和大小,flags参数通常设置为0。recv成功时返回实际读取到的数据的长度,可能小于期望的长度len。因此可能要多次调用recv,才能读取到完整的数据。recv返回0,表示通信对方关闭连接。recv出错返回-1,并设置errno.

send函数flags取值:

0: 与write()无异
MSG_DONTROUTE:告诉内核,目标主机在本地网络,不用查路由表
MSG_DONTWAIT:将单个I/O操作设置为非阻塞模式
MSG_OOB:指明发送的是带外信息

recv函数flags取值:

0:常规操作,与read()相同
MSG_DONTWAIT:将单个I/O操作设置为非阻塞模式
MSG_OOB:指明发送的是带外信息
MSG_PEEK:可以查看可读的信息,在接收数据后不会将这些数据丢失
MSG_WAITALL:通知内核直到读到请求的数据字节数时,才返回。

扩展
在32位机器上:

ssize_t
typedef int ssize_t
size_t
typedef unsigned int size_t
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值