网络函数send sendto recv recvfrom write read

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011425939/article/details/81836689

1、send

头文件

#include < sys/socket.h >

定义函数

ssize_t send (int s,const void *msg,size_t len,int flags);

参数说明
第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程式要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字符数;
第四个参数一般置0。

函数说明:
send() 用来将数据由指定的 socket 传给对方主机。使用 send 时套接字必须已经连接。send 不包含传送失败的提示信息,如果检测到本地错误将返回-1。因此,如果send 成功返回,并不必然表示连接另一端的进程接收数据。所保证的仅是当send 成功返回时,数据已经无错误地发送到网络上。
对于支持为报文设限的协议,如果单个报文超过协议所支持的最大尺寸,send 失败并将 errno 设为 EMSGSIZE ;对于字节流协议,send 会阻塞直到整个数据被传输。

flags 参数有如下的选择:
MSG_DONTROUTE 勿将数据路由出本地网络
MSG_DONTWAIT 允许非阻塞操作(等价于使用O_NONBLOCK)
MSG_EOR 如果协议支持,此为记录结束
MSG_OOB 如果协议支持,发送带外数据
MSG_NOSIGNAL 使用这个标志。目的是不让其发送SIG_PIPE信号,导致程序退出。

返回值

成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

printf("errno %d:%s\n",errno,strerror(errno));
错误代码

EBADF 参数 s 非法的 socket 处理代码。
EFAULT 参数中有一指针指向无法存取的内存空间。
WNOTSOCK 参数 s 为一文件描述词,非 socket。
EINTR 被信号所中断。
EAGAIN 此动作会令进程阻断,但参数 s 的 socket 为不可阻断的。
ENOBUFS 系统的缓冲内存不足。
EINVAL 传给系统调用的参数不正确。

 注意:

1) send先比较发送数据的长度nbytes和套接字sockfd的发送缓冲区的长度,如果nbytes > 套接字sockfd的发送缓冲区的长度, 该函数返回SOCKET_ERROR;

 2) 如果nbtyes <= 套接字sockfd的发送缓冲区的长度,那么send先检查协议是否正在发送sockfd的发送缓冲区中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送sockfd的发送缓冲区中的数据或者sockfd的发送缓冲区中没有数据,那么send就比较sockfd的发送缓冲区的剩余空间和nbytes

 3) 如果 nbytes > 套接字sockfd的发送缓冲区剩余空间的长度,send就一起等待协议把套接字sockfd的发送缓冲区中的数据发送完

 4) 如果 nbytes < 套接字sockfd的发送缓冲区剩余空间大小,send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把套接字sockfd的发送缓冲区中的数据传到连接的另一端的,而是协议传送的,send仅仅是把buf中的数据copy到套接字sockfd的发送缓冲区的剩余空间里)。

 5) 如果send函数copy成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR; 如果在等待协议传送数据时网络断开,send函数也返回SOCKET_ERROR。

 6) send函数把buff中的数据成功copy到sockfd的改善缓冲区的剩余空间后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个socket函数就会返回SOCKET_ERROR。(每一个除send的socket函数在执行的最开始总要先等待套接字的发送缓冲区中的数据被协议传递完毕才能继续,如果在等待时出现网络错误那么该socket函数就返回SOCKET_ERROR)

7) 在unix系统下,如果send在等待协议传送数据时网络断开,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的处理是进程终止。

2、   sendto

头文件:

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

原型:

 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

成功:则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中

send()用于TCP SOCK_STREAM

sendto()用于UDP SOCK_DGRAM, send也支持flags

3、recv

头文件:

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

原型:

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

功能:不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

返回值:若无错误发生,recv()返回读入的字节数。如果连接已中止,返回0。如果发生错误,返回-1,应用程序可通过perror()获取相应错误信息

printf("errno %d:%s\n",errno,strerror(errno));
第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
第三个参数指明buf的长度;
第四个参数一般置0

flags 参数有如下的选择:

MSG_DONTROUTE 绕过路由表查找。这个标志告诉IP.目的主机在本地网络上面,没有必要查找表.这个标志一般用网络诊断和路由程序里面.
MSG_DONTWAIT 仅本操作非阻塞。
MSG_OOB 发送或接收带外数据。
MSG_PEEK 表示只是从系统缓冲区中读取内容,而不清除系统缓冲区的内容.这样下次读的时候,仍然是一样的内容.一般在有多个进程读写数据时可以使用这个标志。
MSG_WAITALL 等待所有数据。

注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

4、recvfrom

头文件:

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

原型:

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

返回值:如果正确接收返回接收到的字节数,失败返回-1。

sockfd:标识一个已连接套接口的描述字。
buf:接收数据缓冲区。
len:缓冲区长度。

flags:调用操作方式。是以下一个或者多个标志的组合体,可通过“ | ”操作符连在一起:
MSG_DONTWAIT:操作不会被阻塞。
MSG_ERRQUEUE: 指示应该从套接字的错误队列上接收错误值,依据不同的协议,错误值以某种辅佐性消息的方式传递进来,使用者应该提供足够大的缓冲区。导致错误的原封包通过msg_iovec作为一般的数据来传递。导致错误的数据报原目标地址作为msg_name被提供。错误以sock_extended_err结构形态被使用,定义如下
#define SO_EE_ORIGIN_NONE 0
#define SO_EE_ORIGIN_LOCAL 1
#define SO_EE_ORIGIN_ICMP 2
#define SO_EE_ORIGIN_ICMP6 3
struct sock_extended_err
{
    u_int32_t ee_errno;
    u_int8_t ee_origin;
    u_int8_t ee_type;
    u_int8_t ee_code;
    u_int8_t ee_pad;
    u_int32_t ee_info;
    u_int32_t ee_data;
};
MSG_PEEK:指示数据接收后,在接收队列中保留原数据,不将其删除,随后的读操作还可以接收相同的数据。
MSG_TRUNC:返回封包的实际长度,即使它比所提供的缓冲区更长, 只对packet套接字有效。
MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。然而,如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。
MSG_EOR:指示记录的结束,返回的数据完成一个记录。
MSG_TRUNC:指明数据报尾部数据已被丢弃,因为它比所提供的缓冲区需要更多的空间。
MSG_CTRUNC:指明由于缓冲区空间不足,一些控制数据已被丢弃。
MSG_OOB:指示接收到out-of-band数据(即需要优先处理的数据)。
MSG_ERRQUEUE:指示除了来自套接字错误队列的错误外,没有接收到其它数据。
src_addr:(可选)指针,指向装有源地址的缓冲区。
addrlen:(可选)指针,指向from缓冲区长度值。

recv()用于TCP SOCK_STREAM

recvfrom()用于UDP SOCK_DGRAM 也支持flags

5、write

头文件:

#include <unistd.h>

原型:

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

fd:文件描述符;
buf:指定的缓冲区,即指针,指向一段内存单元;
nbyte:要写入文件指定的字节数;
返回值:写入文档的字节数(成功);-1(出错),并设置errno变量。

在网络程序中,当我们向套接字文件描述符写时有两可能。
1)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);
}

6、read

头文件:

#include <unistd.h>

原型函数:

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

功能:从fd中读取count内容,存在buf中。

返回:当读成功 时,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);
}

猜你喜欢

转载自blog.csdn.net/u011425939/article/details/81836689