socket编程中的recv函数和send函数

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();
    }
}
发布了100 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/modi000/article/details/105580382
今日推荐