我在linux系统下写了一个socket程序。服务端用C语言实现的,客户端用java实现。
基本流程是客户端给服务端发送一个数据过去,然后服务端返回给客户端返回一个数据回来。
但是我测试的时候发现当服务端的数据长度超过1500个字节的时候,我的客户端只能收到1448个字节,其他的就收不到了。后来发现当网络延时较小的时候,都能收到,但是网络延时较大的时候,后面的字节就收不到了。
请问这是什么原因呢?我只是知道网络传输的MTU一般是1500,是不是分包后,后面的数据丢失了呢?
请了解的朋友给分析一下!谢谢!!
基本流程是客户端给服务端发送一个数据过去,然后服务端返回给客户端返回一个数据回来。
但是我测试的时候发现当服务端的数据长度超过1500个字节的时候,我的客户端只能收到1448个字节,其他的就收不到了。后来发现当网络延时较小的时候,都能收到,但是网络延时较大的时候,后面的字节就收不到了。
请问这是什么原因呢?我只是知道网络传输的MTU一般是1500,是不是分包后,后面的数据丢失了呢?
请了解的朋友给分析一下!谢谢!!
2)贴一下代码。还要想那么多,对你这个程序,MTU不会影响你的,若你的问题属实,几乎肯定你的代码有BUG。
我在两个网络环境下测试过,第一种是当我用ping命令测试网络延时的时候,time=0.1ms左右,数据就不会丢失,第二种网络环境,time=0.3ms左右的时候数据就会丢包,而且很频繁,我只能收到第一个1448的数据包,后面的496数据包就不知道哪去了。后来用tcpdump抓包看了一下,发现数据包在客户端的linux上也确实是接收到了,但是不知道为什么就是收不到。
我在windows系统下测试过,同样的网络环境,但是没出现过一次丢包现象。但是windows和linux的网络数据包头好像是不同的。我已经测试了有好几天了,实在是找不到原因了!我对java了解的不多,大部分都是看手册了解的,所以如果有用的不对的地方还请大家给我指出来!万分感谢啊!服务端(C语言):int main()
{
unsigned char Recv[100],PassWord[20], TmpData[50], pbuf[3], RecvData[100], SendData[1944];
int reval, i;
memset(RecvData, 0, sizeof(RecvData));
memset(Recv, 0, sizeof(Recv));
memset(SendData, '1', sizeof(SendData));
memset(PassWord, 0, sizeof(PassWord));
memset(TmpData, 0, sizeof(TmpData));
memset(pbuf, 0, sizeof(pbuf));
memcpy(pbuf, "ok", sizeof(pbuf));
reval = Sock_ServerInit(&listenfd,6006); //Sock_ServerInit是我自己写的函数
if(reval != 0)
{
printf("Server Init Error!\n");
return -1;
}
printf("Socket Init OK,Begin get data....\n"); i = 0;
while(1)
{
i++;
reval = Sock_Accept(listenfd,&connectfd);//Sock_Accept是我自己写的函数
if(reval == 0)
{
reval = recv(connectfd,Recv,4,0);
printf("recv = %d\n", reval);
if(4 != reval)
{
printf("recv error!code:%04x\n",reval);
return -2;
}
reval = send(connectfd,SendData,sizeof(SendData),10);
printf("send = %d\n", reval);
if(reval < 0)
{
printf("send error!code:%04x\n",reval);
return -2;
} printf("The %d Successed!\n", i);
CloseSocket(connectfd);
}
}
return 0;
}客户端(JAVA语言):public class JavaSocket { public static void main(String[] args) {
try{
while(true){
int loop = getInput("loop:", 3);
if(loop <= 0)
break;
for(int i = 1; i <= loop; i++){
Socket socket=new Socket("192.168.2.123",6006);
socket.setSoTimeout(160*1000);
InputStream in = null;
OutputStream out = null;
in = socket.getInputStream();
out = socket.getOutputStream();
byte[] send = { 0x01, 0x02, 0x03, 0x04 };
System.out.println("send = " + send.length);
out.write(send);
out.flush();
byte[] recv = new byte[2000];
int recvnum = in.read(recv);
System.out.println("recvnum = " + recvnum);
byte[] outdata = new byte[recvnum];
System.arraycopy(recv,0,outdata,0,recvnum);
System.out.println("outdatalen = " + outdata.length);
if(outdata.length == 1944 || outdata.length == 1024)
System.out.println("OK!\nThe " + i + " Successed!");
else
System.out.println("ERROR!");
in.close();
out.close();
socket.close();
}
}
}catch(Exception e){
e.printStackTrace();
} }
public static int getInput(String promptString, int type) {
int out = 0, i = 0;
try {
byte[] inchar = new byte[10];
System.out.print(promptString);
System.in.read(inchar, 0, 10);
if ((inchar[0] == 10) || (inchar[0] == 0x0d)) {
if (type == 1)
return 1;
else if (type == 2)
return 0;
else
return -1;
}
out = Integer.parseInt((new String(inchar)).trim());
} catch (Exception ee) {
return -1;
}
return out;
}
}
int recvnum = in.read(recv);
它不保证:就一次read()就能将C方send()的所有数据就全读进来.尤其是数据量较大的时候.
同样C方也有这个问题.也不能保证一次read()就全部全部读入JAVA方发送出的数据.尤其是数据量较大的时候
因为服务端一次必须要发送1944个字节,所以我在java客户端就必须一次接收1944个字节,请问应该如何进行处理呢?
(基本想法:无论是C,还是JAVA,在接受数据时,都不能保证一次就全接受1944个数据.故要多次读.)
byte[] recv = new byte[2000];
byte[] outdata = new byte[2000];
int total=0;
int recvnum = 0;
while(total<1944)
{
recvnum=in.read(recv);
if(recvnum>0)
{
System.arraycopy(recv,0,outdata,total,recvnum);
total+=recvnum;
}
}
这个代码含义是说:若不到1944个字节就没有数据了,则跳出循环.
以上想法仅供你参考
用缓冲收数据,从缓冲中把包拆出来.
伪代码如:
while(缓冲有空间)
{
recv(buf);
cmd = unpack(buf);
if(cmd 合法)
处理cmd;
}
今天尝试了一下,果然是多循环了一次就能都收全了。
但是奇怪的是,有时候一次就能收全了,有时候要两次,而且如果没有数据了的话,recvnum = in.read(recv); 执行到这句就没有返回了,然后等到超时时间后就报出Read time out的Exception来。不知道是怎么回事。为什么没有了不返回-1呢?是不是后来我把服务端的关闭套接字屏蔽了,然后改成一个长连接了,这样这个socket下次可以继续使用,不知道是不是和这个有关系呢?
呵呵!总之很感谢“云上飞翔”的帮助,目前问题是解决了!o(∩_∩)o...
如果长度不够就等待再下一次循环时recv().
答:有关系。“长连接”时JAVA就读不到-1了。
不过我连接同事写的C的服务端的时候就读不出-1来,他的具体实现我不清楚,因为我没见过他的代码。所以我写的服务端是模仿的他的,还是我对长连接这样理解错了啊?
close是关闭一个连接.长短连接的定义如下:短连接就是一次操作完后断开连接长连接就是一次操作完后不断开连接连接一时保留着
如http协议使用的就是短连接,象游戏服务这类则多数使用长连接.