解决方案】
1. 发送重试,由业务完成。
因为club_l5的send接口不会保留用户发送的内容,在recv失败的情况下,用户发送的数据已经丢失,所以只能由业务进行重试。
结论:否定。由于后端服务器有多台,每次发送的时候并不能不能保证连接的机器还是上次发送的那一台服务器,有可能后端所有的连接都被断开,虽然失败比例有所降低,还是不能解决问题。
2. 修改服务器端关闭连接的等待时间。
治标不治本,可以在紧急情况下使用。
经过和still、allan、robby、steven一起讨论,最佳的方案就是在发送的时候,就能感知到服务器端已经关闭连接,经过讨论,给出以下解决方案:
3. 在send之前对先对read进行selcect,并使用read检验连接的状态。
在send之前先对select函数read进行select,并设置时间参数设为0,select会立即返回,如果有FIN包可立刻知道,再进行read,如果read的返回值 <= 0,则说明连接有问题,或接收到了fin包,此时需关闭连接进行重连。
4. 使用poll()函数是否处于POLLRDHUP(套接字半关闭)状态。
如果是,则关闭连接进行重连,目前还不完全成熟,且不适用于内核版本较低的系统。
5. 使用系统调用getpeername函数加系统错误码的方式检查对端是否关闭连接。
用法如下:if(getpeername (sock, &addr, &len) < 0 && errno == ENOTCONN) 当此条件成立的时候,说明对端已经关闭连接。
6. 发送之前用MSG_PEEK的方式recv。
看recv的返回值是否0字节,如果是0字节,说明对方发送了fin包,已关闭了连接。allan给出TTC中验证连接是否有效的函数:
view plaincopy to clipboardprint?
01.int CPollerObject::CheckLinkStatus(void)
02.{
03. char msg[1] = {0};
04. int err = 0;
05. err = recv(netfd, msg, sizeof(msg), MSG_DONTWAIT|MSG_PEEK);
06. /* client already close connection. */
07. if(err == 0 || (err < 0 && errno != EAGAIN))
08. return -1;
09. return 0;
10.}
int CPollerObject::CheckLinkStatus(void)
{
char msg[1] = {0};
int err = 0;
err = recv(netfd, msg, sizeof(msg), MSG_DONTWAIT|MSG_PEEK);
/* client already close connection. */
if(err == 0 || (err < 0 && errno != EAGAIN))
return -1;
return 0;
}
阅读(525) | 评论(0) | 转发(0) |