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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
send函数recv函数是VC++Socket编程最常用的两个函数,它们分别用于发送数据和接收数据。 send函数的原型如下: ```c++ int send( SOCKET s, const char* buf, int len, int flags ); ``` 参数说明: - s:需要发送数据的Socket。 - buf:指向包含要发送数据的缓冲区的指针。 - len:要发送的数据的字节数。 - flags:调用方式标志。 返回值说明: - 成功:返回实际发送的字节数。 - 失败:返回SOCKET_ERROR。 recv函数的原型如下: ```c++ int recv( SOCKET s, char* buf, int len, int flags ); ``` 参数说明: - s:需要接收数据的Socket。 - buf:指向接收数据的缓冲区的指针。 - len:要接收的数据的最大字节数。 - flags:调用方式标志。 返回值说明: - 成功:返回实际接收的字节数。 - 失败:返回SOCKET_ERROR。 sendrecv函数的使用方法如下: ```c++ char sendbuf[] = "Hello, world!"; int sendbuflen = sizeof(sendbuf); int sentbytes = 0; sentbytes = send(sock, sendbuf, sendbuflen, 0); if (sentbytes == SOCKET_ERROR) { // 发送失败 } char recvbuf[1024]; int recvbuflen = sizeof(recvbuf); int receivedbytes = 0; receivedbytes = recv(sock, recvbuf, recvbuflen, 0); if (receivedbytes == SOCKET_ERROR) { // 接收失败 } ``` 使用sendrecv函数时需要注意以下几点: - sendrecv函数都是阻塞式的,即程序会一直等待直到发送或接收完所有数据。 - 如果发送或接收的数据量比较大,需要多次调用sendrecv函数。 - 如果发送或接收的数据量比较小,建议使用TCP_NODELAY选项关闭Nagle算法,以提高发送和接收的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值