还是搞不定,socket的问题,一解决就给分!

ysli 2001-09-18 06:00:25
下面的程序为服务端,试图从客户端接收一个长度为8192的流式包,可为什么只能接受到1460呢(客户端没问题,发出8192)??不是说流式数据不受大小限制么?(见http://www.csdn.net/expert/topicview1.asp?id=275250)
请各位出手,谢谢!!

#include <sys/types.h>
#include <sys/mntent.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define USERPORT 10002 /*port number*/

main(int argc,char **argv)
{
char buf_in[8192]; /*may be a SQL from client*/
char buf_out[8192]; /*may be a result to clinet*/

struct sockaddr_in client;
struct sockaddr_in server;

int s;
int ns;
int namelen;
int pktlen;

if((s=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("Socket()");
return;
}
/* first step:socket*/

bzero((char *)&server,sizeof(server));

server.sin_family = AF_INET;
server.sin_port = htons(USERPORT);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr *)&server, sizeof(server))<0)
{
perror("Bind()");
return;
}
/*sencond step:bind*/

for(;;)
{
if (listen(s,1)!=0) /*only one client and standing listen*/
{
perror("Listen()");
return;
}
/*third step:listen*/

namelen = sizeof(client);
if ((ns = accept(s, (struct sockaddr *)&client, &namelen)) ==-1)
{
perror("Accept()");
return;
}
/*fourth step:accept*/

if ((pktlen = recv(ns,buf_in,8192,0))<0)
{
perror("Recv()");
break;
}
else
if (pktlen == 0)
{
printf("Recv():return FAILED,connection is shut down!\n");
break;
}
else
printf("Recv():return SUCCESS,packet length = %d\n",pktlen);
printf("buf_in is :%s\n",&buf_in);
/*fifth step:recv*/

/*sleep(1); */
if (send(ns,buf_out,pktlen,0)<0)
{
perror("Send()");
break;
}
else
printf("Send():return SUCCESS,packet length = %d\n",pktlen);
/*sixth step:send*/
}

close(ns);
close(s);
}
...全文
841 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
dp_computer 2001-09-23
  • 打赏
  • 举报
回复
同意,我也遇到过这样得问题。
就时'\0'得问题。
HUANG_JH 2001-09-22
  • 打赏
  • 举报
回复
学习
stlyy 2001-09-22
  • 打赏
  • 举报
回复
不合常例,但程序可以运行,因为你是单用户连接,无限循环实际没有用处,服务器运行后会在accept处阻塞,接到一个连接,循环会停止,接收函数没有错误,但在接收缓冲区中只有1460的数据,不会有错误,原因只能是发送方根本没有发送大于1460个字节的数据,原因有可能是znmeng(fish) 估计的,因为strlen遇到‘\0’就会认为字符串结束,而得出的长度并非要发送的字节数目,建议跟踪发送端的send函数中的长度值,可能会有结果。
znmeng 2001-09-21
  • 打赏
  • 举报
回复
实际上你可以在本机上进行主机跟客户机的通讯过程,然后再放在广域网上使用,你上面的程序没有问题,是对的。

问题可能是出现在你的客户端程序上,你检查你的客户端程序的发送函数调用中
的发送长度是否为固定的数字,如果你要是用了strlen()函数来判断发送字符串长度,那肯定发送长度错了。

还有你上面的程序使用的是阻塞接收,使用的流方式(TCP方式)接收,不管你发送的字节多少(可能有2M,也不会丢包或者有误这是TCP协议传输所规定的),都可以正常的接收到。
binglex 2001-09-20
  • 打赏
  • 举报
回复
把listen拿到for(;;)之外,而把accept和recv放在循环里,就可以接收多次client的发送了,

dansu:
3.你接收的时候整个主线程就阻塞在那儿,这个方法不好.

当然使用单独线程处理每个client的连接请求是标准做法,不过如果每个连接的处理时间很短,单线程也可以
binglex 2001-09-20
  • 打赏
  • 举报
回复
因为服务器先recv,然后client发,他一次最多只能发一个mtu的数据,这样8192 bytes数据分几个数据报发出,第一个数据报到达可能服务端就recv成功,然后返回,所以你收到1500bytes。在以太网里,windows机器第一次收到的数据报可能长达10000多个bytes。不过还是不能因此使用一次接收全部发送的数据,因为对于不同的计算机之间第一次的数据长度是不定的。

就是说recv接收的包没有限制(<=65535),但是如果数据缓冲区没有那么多,那他就会尽快返回了,所以还是用我上面的接收代码把:循环接收,直到结束或者出错。

zb_china 2001-09-20
  • 打赏
  • 举报
回复
客户端本来就是分几次发送的,只不过将发送的数据提交给系统是一次调用完成的。
laynx 2001-09-20
  • 打赏
  • 举报
回复
accept也应该放到循环外。
除非有多个客户端或者客户端会多次调用connect/close(shutdown)
dansu 2001-09-20
  • 打赏
  • 举报
回复
自己多看一些书比问人好,别人就算告诉你,你也不一定明白.
1.你把LISTEN放入循环肯定是错的.
2.RECV不可能那么准确的收到你想要的那么多数据的,因为INTERNET不是一个理想的状态(也有一些规定).
3.你接收的时候整个主线程就阻塞在那儿,这个方法不好.
ysli 2001-09-20
  • 打赏
  • 举报
回复
小结一下:
一个recv最多就只能接收1500字节的数据,但缓冲区里不一定只有1500,所以可以用多个recv循环接收。
是这样的吗?看看有没有其他高见?中午结贴,感谢!
dark_will 2001-09-20
  • 打赏
  • 举报
回复
:o
我不懂电脑 2001-09-20
  • 打赏
  • 举报
回复
心情很糟,无心答题。
ysli 2001-09-20
  • 打赏
  • 举报
回复
多谢各位!
getmoon 2001-09-19
  • 打赏
  • 举报
回复
快点看书吧,吧listen放在外面,然后accept以后fork一个子进程,由这个子进程来循环接收数据。
ysli 2001-09-19
  • 打赏
  • 举报
回复
to hellion:是呀我刚刚学socket,赶快看书去了...
可是本贴的110分给谁呢?我的贴一向是很快给分的,怎办呢?
还是清各位再指教呀!

harrin 2001-09-19
  • 打赏
  • 举报
回复
小伙,IP分包了,这么大的数据,哪个链路上会有8K多的MTU呢?多等待一会吧!
hellion 2001-09-19
  • 打赏
  • 举报
回复
to ysli(落叶松)
你对socket没有理解好,看看书吧
ysli 2001-09-19
  • 打赏
  • 举报
回复
to caiyi9000:我按照你的说法试了一下,还是不行么,send和recv根本就不理我,555......
ysli 2001-09-19
  • 打赏
  • 举报
回复
to getmoon:我把listen放到循环中是这样想的:每个listen(s,1)只接收一条请求,然后循环中对此请求进行处理,完成后再listen()接收下一条请求,不知道这样想对不对哦?
binglex 2001-09-19
  • 打赏
  • 举报
回复
recv一次不能受到那么大的包,一般以太网的mtu是1500,加上tcp ip包头的40bytes,你一次收到的数据恰好是1460bytes。你应该把recv放在循环里,直到recv返回值<=0就break。

int recvlen;
pktlen = 0;
while ((recvlen = recv(ns, &buf_in[pktlen],8192 - pktlen,0)) > 0)
{
pktlen += recvlen;
}

if(recvlen == 0)
{ printf("Recv() SUCCESS, packet length = %d\n",pktlen);
printf("buf_in is :%s\n", buf_in);
}

/*fifth step:recv*/

if(recvlen < 0)
{
perror("Recv()");
break;
}

if (recvlen < 0)
{
printf("Recv():return FAILED, break recv!\n");
break;
}


加载更多回复(12)

4,356

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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