一旦,我们建立好了tcp连接之后,我们就可以把得到的fd当作文件描述符来使用。

由此网络程序里最基本的函数就是read和write(int fd, const void*buf,size_t nbytes);

write的返回值大于0,表示写了部分或者是全部的数据. 这样我们用一个while循环来不停的写入,但是循环过程中的buf参数和nbyte参数得由我们来更新。也就是说,网络写函数是不负责将全部数据写完之后在返回的。

2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理.

如果错误为EINTR表示在写的时候出现了中断错误.

如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).

为了处理以上的情况,我们自己编写一个写函数来处理这几种情况.


int my_write(int fd,void *buffer,int length)

{

int bytes_left;

int written_bytes;

char *ptr;


ptr=buffer;

bytes_left=length;

while(bytes_left>0)

{

        

         written_bytes=write(fd,ptr,bytes_left);

         if(written_bytes<=0)

         {       

                 if(errno==EINTR)

                         written_bytes=0;

                 else             

                         return(-1);

         }

         bytes_left-=written_bytes;

         ptr+=written_bytes;     

}

return(0);

}


读函数read

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

read函数是负责从fd中读取内容.当读成功 时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.如果错误为EINTR说明读是由中断引起 的, 如果是ECONNREST表示网络连接出了问题. 和上面一样,我们也写一个自己的读函数.


int my_read(int fd,void *buffer,int length)

{

int bytes_left;

int bytes_read;

char *ptr;

  

bytes_left=length;

while(bytes_left>0)

{

    bytes_read=read(fd,ptr,bytes_read);

    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);

}


数据的传递

有了上面的两个函数,我们就可以向客户端或者是服务端传递数据了.比如我们要传递一个结构.可以使用如下方式




struct my_struct my_struct_client;

write(fd,(void *)&my_struct_client,sizeof(struct my_struct);



char buffer[sizeof(struct my_struct)];

struct *my_struct_server;

read(fd,(void *)buffer,sizeof(struct my_struct));

my_struct_server=(struct my_struct *)buffer;    


在网络上传递数据时我们一般都是把数据转化为char类型的数据传递.接收的时候也是一样的注意的是我们没有必要在网络上传递指针(因为传递指针是没有任何意义的,我们必须传递指针所指向的内容)



6.1 recv和send函数提供了和read和send(int sockfd,void *buf,int len,int flags)


前面的三个参数和read,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 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 optionSO_NOSIGPIPE​ ​?​​. 对于服务器端,我们可以使用这个标志。目的是不让其发送SIG_PIPE信号,导致程序退出。

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


一个奔跑的程序员