1、recv()函数
recv()函数用于socket通信中接收消息
#include <sys/types.h>
#include<sys/socket.h>
ssize_t recv(int sockfd, void *buff,size_t nbytes,int flags);
sockfd:文件描述符;
buff:指向一个缓冲区,用来存放接收的数据
nbytes:指明buff的长度
flags:一般置为0
返回值:失败,返回小于0;超时或对端主动关闭,返回0;成功,返回接收的数据长度
解释:虽然接收报文的缓冲区buff长度为nbytes,但是每次接收的数据不一定就是nbytes,nbytes只是说容器的长度。
int receivefunc()
{
//一般先接收一次报头,报头确认后再接着接收剩下的报文
/*
接收并确认是已知的报文头;
*/
char buff[128] = {0};
int length = N //N为已知的报文的长度字节数
fd_set r_set;
struct timeval w_time;
w_time.tv_sec = 3;
w_time.tv_usec = 0;
FD_ZERO(&fd_recv);
FD_SET(connfd,&r_set);
while(1)
{
int ret = select(connfd+1,&fd_recv,(fd_set*)0,(fd_set*)0,&w_time);
if(ret <0)
{
if((errno == EINTR)||(errno== EAGAIN))
continue;
printf("select error:%s\n",strerror(errno));
return -1;
}else if(ret == 0){
printf("select timeout:%s\n",strerror(errno));
return 0;
}else
break;
}
if(FD_ISSET(connfd,&r_set)
{
int irecv,iunrecv;
iunrecv = length;
while(iunrecv>0)
{
irecv = recv(concfd,buff,iunrecv,0)
if(irecv==0)
{
printf("recv error:%s",strerror(errno));
return -1;
}
if(irecv<0)
{
if(errno == EINTR ||(errno == EAGAIN)||errno == EWOULDBLOCK)
continue;
printf("recv error:%s",strerror(errno));
return -1;
}
iunrecv -= irecv;
buff += irecv;
}
}
}
小结:recev()函数不一定能将要发送的数据一次性接收完,所以要进行循环接收;
2、send()函数
#include <sys/types.h>
#include<sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
sockfd:发送端套接字描述符
buf:指向要发送的数据 //char ch[N];数组
nbytes:实际要发送的数据的字节数//每次不一定都能发送完
flags:一般置为0
返回值:失败,返回值小于0;超时或对端主动关闭,返回0;成功,返回发送数据的长度。
send和write的唯一区别就是最后一个参数flags的存在,当flags为0时,send和wirte等价。
send函数调用后:比较nbytes与套接字sockfd发送缓冲的长度blength:
1)nbytes>blength,函数返回SOCKET_ERROR;
2)nbytes<=blength,
a)send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完;
b)如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和nbytes
i)如果nbytes大于剩余空间大小,send就一直等待协议把s的发送缓冲中的数据发送完,
ii)如果nbytes小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)
如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。
小结:nbytes<=blength的情况说了这么多,其实不管过程的话,只要copy没有错误,此时是可以正常发送的。
int sendfunc()
{
char buff[128] = {0};
memcpy(buff....);//buff中存储的要send的数据
int length = strlen(buff);//buff中的数据长度
fd_set w_set;
struct timeval w_time;
w_time.tv_sec = 3;
w_time.tv_usec = 0;
FD_ZERO(&fd_send);
FD_SET(connfd,&w_set);
while(1)
{
int ret = select(connfd+1,(fd_set*)0,&w_set,(fd_set*)0,&w_time);
if(ret <0)
{
if((errno == EINTR)||(errno== EAGAIN))
continue;
printf("select error:%s\n",strerror(errno));
return -1;
}else if(ret == 0){
printf("select timeout:%s\n",strerror(errno));
return 0;
}else
break;
}
if(FD_ISSET(connfd,&w_set)
{
int isend,iunsend;
iunsend = length;
while(iunsend>0)
{
isend = send(concfd,buff,iunsend,0)
if(isend<=0)
{
printf("send error:%s",strerror(errno));
return -1;
}
iunsend -= isend;
buff += isend;
}
}
}
小结:send()函数不一定能将要发送的数据一次性发送完,所以要进行循环发送;
int main()
{
socket();
connect();
while(1)
{
receivefun();
sendfun();
}
}