linux下tcp通信实例,Linux下使用TCP通讯时遇到问题的解决实例

在这里总结一下这Linux用TCP通讯需要注意的几个问题,都是前一阵子工作中遇到的问题。

问题1. 发送和接收数据时的不完整问题

以接收为例,当对端发送1000个字节的数据时,本端进行接收,会出现调用recv返回500并且errno==EAGAIN的情况(测试中发现这种情况非常严重),这个错误表示当前设备忙,稍后再试。理想化的解决办法是这样的:

使用select或者epoll机制,当有数据到来时,select或epoll会通知,此时一直接收直到recv返回0表示所有数据都接收完。过程中当errno==EAGAIN则暂停接收,并将已经接收的数据缓存起来。当设备再次可读时select或者epoll会再次通知,在缓存数据的后面继续接收,如此反复n次直到recv返回值为0。

但是这种方法需要把已经接收的部分数据进行缓存,实现起来非常繁琐,我进行了如下的简单实现,是我封装的epoll中的部分代码:

int

mo_epoll_recv (int s, void* buf, int buf_size, int err)

{

int recved_len = 0;

int total_recv_len = 0;

int count = 0;

if (buf == NULL || buf_size <= 0)

{

return -1;

}

MO_DEBUG ("to recv some data!\n");

do

{

//MO_DEBUG ("call recv, total_recv_len=%d recv_len=%d\n", total_recv_len, buf_size-total_recv_len);

recved_len = recv (s, buf+total_recv_len, buf_size-total_recv_len, err);

//MO_DEBUG ("called recv, recved_len=%d\n, errno=%d:EAGAIN=%d:%s\n", recved_len, errno, EAGAIN, strerror (errno));

if (recved_len < 0 && errno != EAGAIN)

{

MO_ERROR ("some error when recv erron: %d, %s", errno, strerror (errno));

break;

}

else if (recved_len < 0 && errno == EAGAIN)

{

recved_len = 1;

/* 10s timeout */

if (++count > 200)

{

break;

}

usleep (1000*50);

continue;

}

total_recv_len += recved_len;

if (total_recv_len >= buf_size)

{

recved_len = 0;

//MO_DEBUG ("recv %d bytes!!!!!", total_recv_len);

break;

}

usleep (1000*50);

}while(recved_len > 0);

MO_DEBUG ("recv some data over %d bytes!\n", total_recv_len);

if (recved_len == -1)

return -1;

return total_recv_len;

}

int

mo_epoll_send (int s, const void* buf, int buf_size, int err)

{

int sended_len = 0;

int total_send_len = 0;

if (buf == NULL || buf_size <= 0)

{

return -1;

}

MO_DEBUG ("to send some data!\n");

do

{

sended_len = send (s, (buf+total_send_len), buf_size-total_send_len, err);

if (sended_len == -1 && errno != EAGAIN)

{

break;

}

else if (sended_len == -1 && errno == EAGAIN)

{

sended_len = 1;

continue;

}

total_send_len += sended_len;

if (total_send_len >= buf_size)

{

sended_len = 0;

//MO_DEBUG ("send %d bytes!!!!!", total_send_len);

break;

}

}while(sended_len > 0);

MO_DEBUG ("send some data over %d bytes!\n", total_send_len);

if (sended_len == -1)

return -1;

return total_send_len;

}

问题2. 干净的关闭socket,应该使用如下方法来关闭你不使用的socket,不要仅仅调用close():

void

cleanclose (int s)

{

int i = 0;

char buf[100];

/* 关闭写入 */

shutdown (s, SHUT_WR);

/* 接收所有数据 */

do

{

i = recv (s, buf, 100, 0);

}while (i > 0);

/* 关闭读取 */

shutdown (s, SHUT_RD);

/* 关闭socket */

close (s);

}0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值