cs模式下,改小了服务端的缓冲区大小,客户端socket总是recv返回0的问题

martingod 2011-11-18 03:22:10
客户端和服务端socket设置为非阻塞模式。客户端和服务端均为单线程。
客户端和服务端均在一台机器上,2个进程,只有一个客户端。客户端固定发40k大小的包,服务端收到了原包返回,其中的包序列号累加做校验。

一开始我设置服务端的接收和发送缓冲均为32k,收发均正常。后来我为了测试发送和接收返回-1的情况,将服务端的发送缓冲区和接收缓冲区改小到16k。
互发的第一包ok,而且看到分了多次发送。但是第二包客户端发送成功后就收到了recv = 0。这种情况应该是服务端断开了连接,但是我打断点close始终没有断到服务端有这样的行为。
请有经验的兄弟帮忙看看是我的程序有问题还是单纯就是缓冲区太小的问题
...全文
236 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
martingod 2011-11-21
  • 打赏
  • 举报
回复
找到原因了,write函数中拷贝代码多了下面几行,因此导致写完数据后把socket给关掉了。而这段代码只在发生重写时存在。
g_io_channel_unref(gio);
g_io_channel_shutdown(gio, TRUE, NULL);
c->write_channel = NULL;

to 楼上的,我测试了下,ret < 0在非阻塞模式下不是断开。read = 0才是。
ma100 2011-11-21
  • 打赏
  • 举报
回复
ret <0 才是断开
martingod 2011-11-21
  • 打赏
  • 举报
回复
gboolean LinkAddWriteEvent(int sockfd, READ_HANDLER handler, gpointer conn)
{
connection_t *write_conn = (connection_t *)conn;

GIOChannel *channel = g_io_channel_unix_new(sockfd);
if(!channel)
{
g_error("CREATE GIOChannle error.\n");
return FALSE;
}

g_io_channel_set_close_on_unref(channel, TRUE);

GIOCondition cn = (GIOCondition)(G_IO_OUT |G_IO_HUP);
write_conn->write_sourceid = g_io_add_watch(channel, cn, handler, conn);

if(!write_conn->write_sourceid)
{
printf("Cannot add watch on GIOChannel!\n");
return FALSE;
}

write_conn->write_channel = channel;
return TRUE;
}

int LinkSendPkg(connection_t *c, char *buf, int buflen)
{
//change to json format.
int writebytes = 0;
sendpkt_t *pkt = NULL;
sendpkt_t *tmp_pkt = NULL;
char *send_pkt = NULL;

LinkPkgHead *pstHead = (LinkPkgHead *)buf;

writebytes = write(c->fd, buf, buflen);
if((writebytes < 0) &&
(errno != EAGAIN && errno != EINTR))
{
goto write_error;
}
else
{
if(writebytes >= buflen)
{
printf("write total %d pkt ver[%d] type[%d] from[%d] to[%d].\n",
buflen, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);
dwTmpSeq = pstHead->dwType + 1;
}
else
{
//append to write list and create write event monitor.
printf("write part :%d , total_len is %d ver[%d] type[%d] from[%d] to[%d]\n",
writebytes, buflen, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);

pkt = (sendpkt_t *)malloc(sizeof(sendpkt_t));
if(pkt == NULL)
{
printf("malloc error for pkt in %s\n", __func__);
return -1;
}

memset(pkt, 0, sizeof(sendpkt_t));

send_pkt = (char *)malloc(buflen);
if (NULL == send_pkt)
{
printf("malloc error for send_pkt in %s\n", __func__);
free(pkt);
return -1;
}

memset(send_pkt, 0, buflen);
memcpy(send_pkt, buf, buflen);

pkt->buflen = buflen;
pkt->sent = writebytes;
pkt->sendbuf = send_pkt;
pkt->next = NULL;

if(c->wbuf_list == NULL)
{
c->wbuf_list = pkt;

}
else
{
tmp_pkt = c->wbuf_list;
while(tmp_pkt->next != NULL)
{
tmp_pkt = tmp_pkt->next;
}
tmp_pkt->next = pkt;
}

//add to epoll monitor.
LinkAddWriteEvent(c->fd, LinkWriteEvent, c);
}
}

return 0;

write_error:
LinkCloseConnect(c);
return -1;
}

gboolean LinkWriteEvent(GIOChannel *gio, GIOCondition condition, gpointer data)
{
int writebytes = 0;
sendpkt_t *snd_pkt = NULL, *free_pkt= NULL;
connection_t *c = (connection_t *)data;

if(condition & G_IO_HUP)
{
printf("end ot pipe died.!!\n");
//close the connection;
goto sockfd_error;
}

snd_pkt = c->wbuf_list;
snd_pkt->resendcnt++;
if (MAX_RESEND_CNT < snd_pkt->resendcnt)
{
printf("resent cnt = %d is too much. \n", snd_pkt->resendcnt);
goto sockfd_error;
}

while(snd_pkt)
{
writebytes = write(c->fd, snd_pkt->sendbuf + snd_pkt->sent, snd_pkt->buflen - snd_pkt->sent);
if(writebytes < 0)
{
printf("writebytes error. \n");
if(errno != EAGAIN)
{
goto sockfd_error;
}
return TRUE;
}
else if (0 == writebytes)
{
printf("socket is close. \n");
goto sockfd_error;
}

snd_pkt->sent += writebytes;
LinkPkgHead *pstHead = (LinkPkgHead *)(snd_pkt->sendbuf);
if(snd_pkt->sent != snd_pkt->buflen)
{
printf("write %d of total pkt %d, this time write %d bytes. ver[%d] type[%d] from[%d] to[%d] \n",
snd_pkt->sent, snd_pkt->buflen, writebytes, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);

return TRUE;

}
else
{
printf("write total pkt. %d. ver[%d] type[%d] from[%d] to[%d]\n",
snd_pkt->sent, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);
dwTmpSeq = pstHead->dwType + 1;
//free snd_pkt.
free_pkt = snd_pkt;
snd_pkt = snd_pkt->next;
free(free_pkt->sendbuf);
free(free_pkt);
}
}

//set wbuf_list to NULL if send pkt list sent.
if(snd_pkt == NULL)
{
c->wbuf_list = NULL;
}

//remove from event list.
g_source_remove(c->write_sourceid);
c->write_sourceid = 0;

g_io_channel_unref(gio);
g_io_channel_shutdown(gio, TRUE, NULL);
c->write_channel = NULL;

return TRUE;

sockfd_error:
LinkCloseConnect(c);
return FALSE;
}
martingod 2011-11-21
  • 打赏
  • 举报
回复
写接口实现
int LinkSendPkg(connection_t *c, char *buf, int buflen)
{
//change to json format.
int writebytes = 0;
sendpkt_t *pkt = NULL;
sendpkt_t *tmp_pkt = NULL;
char *send_pkt = NULL;

LinkPkgHead *pstHead = (LinkPkgHead *)buf;

writebytes = write(c->fd, buf, buflen);
if((writebytes < 0) &&
(errno != EAGAIN && errno != EINTR))
{
goto write_error;
}
else
{
if(writebytes >= buflen)
{
printf("write total %d pkt ver[%d] type[%d] from[%d] to[%d].\n",
buflen, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);
dwTmpSeq = pstHead->dwType + 1;
}
else
{
//append to write list and create write event monitor.
printf("write part :%d , total_len is %d ver[%d] type[%d] from[%d] to[%d]\n",
writebytes, buflen, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);

pkt = (sendpkt_t *)malloc(sizeof(sendpkt_t));
if(pkt == NULL)
{
printf("malloc error for pkt in %s\n", __func__);
return -1;
}

memset(pkt, 0, sizeof(sendpkt_t));

send_pkt = (char *)malloc(buflen);
if (NULL == send_pkt)
{
printf("malloc error for send_pkt in %s\n", __func__);
free(pkt);
return -1;
}

memset(send_pkt, 0, buflen);
memcpy(send_pkt, buf, buflen);

pkt->buflen = buflen;
pkt->sent = writebytes;
pkt->sendbuf = send_pkt;
pkt->next = NULL;

if(c->wbuf_list == NULL)
{
c->wbuf_list = pkt;

}
else
{
tmp_pkt = c->wbuf_list;
while(tmp_pkt->next != NULL)
{
tmp_pkt = tmp_pkt->next;
}
tmp_pkt->next = pkt;
}

//add to epoll monitor.
LinkAddWriteEvent(c->fd, LinkWriteEvent, c);
}
}

return 0;

write_error:
LinkCloseConnect(c);
return -1;
}

gboolean LinkWriteEvent(GIOChannel *gio, GIOCondition condition, gpointer data)
{
int writebytes = 0;
sendpkt_t *snd_pkt = NULL, *free_pkt= NULL;
connection_t *c = (connection_t *)data;

if(condition & G_IO_HUP)
{
printf("end ot pipe died.!!\n");
//close the connection;
goto sockfd_error;
}

snd_pkt = c->wbuf_list;
snd_pkt->resendcnt++;
if (MAX_RESEND_CNT < snd_pkt->resendcnt)
{
printf("resent cnt = %d is too much. \n", snd_pkt->resendcnt);
goto sockfd_error;
}

while(snd_pkt)
{
writebytes = write(c->fd, snd_pkt->sendbuf + snd_pkt->sent, snd_pkt->buflen - snd_pkt->sent);
if(writebytes < 0)
{
printf("writebytes error. \n");
if(errno != EAGAIN)
{
goto sockfd_error;
}
return TRUE;
}
else if (0 == writebytes)
{
printf("socket is close. \n");
goto sockfd_error;
}

snd_pkt->sent += writebytes;
LinkPkgHead *pstHead = (LinkPkgHead *)(snd_pkt->sendbuf);
if(snd_pkt->sent != snd_pkt->buflen)
{
printf("write %d of total pkt %d, this time write %d bytes. ver[%d] type[%d] from[%d] to[%d] \n",
snd_pkt->sent, snd_pkt->buflen, writebytes, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);

return TRUE;

}
else
{
printf("write total pkt. %d. ver[%d] type[%d] from[%d] to[%d]\n",
snd_pkt->sent, pstHead->dwVer, pstHead->dwType, pstHead->dwFromId, pstHead->dwToId);
dwTmpSeq = pstHead->dwType + 1;
//free snd_pkt.
free_pkt = snd_pkt;
snd_pkt = snd_pkt->next;
free(free_pkt->sendbuf);
free(free_pkt);
}
}

//set wbuf_list to NULL if send pkt list sent.
if(snd_pkt == NULL)
{
c->wbuf_list = NULL;
}

//remove from event list.
g_source_remove(c->write_sourceid);
c->write_sourceid = 0;

g_io_channel_unref(gio);
g_io_channel_shutdown(gio, TRUE, NULL);
c->write_channel = NULL;

return TRUE;

sockfd_error:
LinkCloseConnect(c);
return FALSE;
}
martingod 2011-11-21
  • 打赏
  • 举报
回复
读接口实现
gboolean LinkReadEvent(GIOChannel *gio, GIOCondition condition, gpointer data)
{
int readbytes;
LinkPkgHead *pstPkgHead = NULL;
connection_t *c = (connection_t *)data;

if(condition & G_IO_HUP)
{
printf("read end ot pipe died.!!\n");
//close the connection;
goto sockfd_error;
}

while (TRUE)
{
readbytes = read(c->fd, c->readbuf + c->read_len, sizeof(c->readbuf) - c->read_len);
if (readbytes < 0)
{
if (EINTR == errno || errno == EAGAIN)
{
break;
}
else
{
printf("sock is error. errno is %d\n", errno);
goto sockfd_error;
}
}
else if (0 == readbytes)
{
printf("socket read return 0 .\n");
goto sockfd_error;
}
else
{
c->read_len += readbytes;
if(c->read_len > MAX_READBUF_LEN)
{
printf("c->read_len %d is more than MAX_READBUF_LEN %d\n", c->read_len , MAX_READBUF_LEN);
goto sockfd_error;
}

if (INVALID_PKG_LEN == c->pkt_len)
{
if(c->read_len >= (int)(sizeof(LinkPkgHead)))
{
pstPkgHead = (LinkPkgHead *)(c->readbuf);
c->pkt_len = pstPkgHead->dwLen + sizeof(LinkPkgHead);
if (c->pkt_len <= 0 || c->pkt_len > MAX_READBUF_LEN)
{
printf("pkt_len = %d is invalid.\n", c->pkt_len);
goto sockfd_error;
}
}
else
{
continue;
}
}

if(c->pkt_len > c->read_len)
{
//have not recv total pkt.
printf("read len = %d in total %d \r\n", c->read_len, c->pkt_len);
continue;
}

//call the user-defined read_pkt.
c->read_pkt(c, c->readbuf, c->pkt_len);

//reset the len value
if (c->read_len >= c->pkt_len)
{
memmove(c->readbuf, c->readbuf + c->pkt_len, c->read_len - c->pkt_len);
c->read_len = c->read_len - c->pkt_len;
}

}
}

return TRUE;

sockfd_error:
LinkCloseConnect(c);
return FALSE;
}
nanjingnew4 2011-11-19
  • 打赏
  • 举报
回复
代码呢?
yby4769250 2011-11-19
  • 打赏
  • 举报
回复
在客户端getlasterror看看返回的错误码是多少。
或者抓包,commview或者其他工具,同一台机子测试的话,设置成loopback模式,然后看看服务器端有没有发送FIN包
qq120848369 2011-11-18
  • 打赏
  • 举报
回复
你贴代码我们看下。
martingod 2011-11-18
  • 打赏
  • 举报
回复
难道连续2个问题都米人关注了。。。太伤心了

23,121

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧