急! socket 客户端接收大于10K的数据,接收不完整

banditgao 2015-04-13 10:40:54
我对socket不熟悉,但是这个事挺急,请各位帮我看看。谢谢了啊 ,分不够再加!!!

socket 向服务端请求数据,返回的数据如果小于10K,那么能看到xml的整个完整的格式如下:
<?xml version="1.0" encoding="GBK"?>
<root>
<header>
<name>
....
</name>
.....
</header>
</root>

如果大于10K,XML就不完整了,解析出来少了一部分,反正看不到结尾的</root>节点.... 换成循环读取貌似也是一样。。客户端代码如下:




public String buildSocket4Sync(SocketConn sm, HostVO address, String cmd)
{
BufferedReader br = null;
InputStream in = null;
String result = "";
try
{
socket = new Socket(address.getIp(), address.getPort());
OutputStream socketOut = socket.getOutputStream();
socketOut.write(cmd.getBytes());
socketOut.write("\r\n".getBytes());

in = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(in, "utf-8"));
String re;
StringBuffer sbf = new StringBuffer();
while ((re = br.readLine()) != null)
{
sbf.append(re);
}

if (sbf.length() != 0)
{
result = new String(Base64.decode(sbf.toString()), "utf-8");
// System.out.println(result);

}

}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (null != br)
{
br.close();
}
in.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
return result;
}



急啊,感谢感谢!
...全文
612 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
lsongiu86 2015-04-16
  • 打赏
  • 举报
回复
引用 16 楼 micropentium6 的回复:
引用 12 楼 lsongiu86 的回复:
[quote=引用 11 楼 banditgao 的回复:] 使用MINA也需要约定 数据的格式吗? 比如 数据总长度+字节数 ?
对的,nio会有粘包发生的
不是nio揍木有粘包了吗?[/quote]没错,tcp都有粘包,不是nio的感觉好处理一点点
  • 打赏
  • 举报
回复
引用 12 楼 lsongiu86 的回复:
引用 11 楼 banditgao 的回复:
使用MINA也需要约定 数据的格式吗? 比如 数据总长度+字节数 ?
对的,nio会有粘包发生的
不是nio揍木有粘包了吗?
banditgao 2015-04-15
  • 打赏
  • 举报
回复
CumulativeProtocolDecoder 用这个做解码器,数据一大也是NULL。。。 正在用TCPDUMP抓包,看看再说
疯狂熊猫人 2015-04-14
  • 打赏
  • 举报
回复
@Override public void messageReceived(IoSession session, Object message) throws Exception { logger.debug("Receive Server message " + message); super.messageReceived(session, message); releaseSession(session); } 这里是不是不应该 releaseSession(session);呢?
banditgao 2015-04-14
  • 打赏
  • 举报
回复
我是楼主,服务器端是用MINA做的,没有分包,直接全部发出来。 然后下面用这个类接收和解析,但是数据库量小还是好的,数据量大还是不行


package com.net.base.action;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;

import org.apache.mina.core.RuntimeIoException;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.future.ReadFuture;
import org.apache.mina.core.future.WriteFuture;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.net.exception.BusinessException;
import com.net.util.Logger;
import com.net.test.minaSocket.Base64;

/**
 * 
 * <code>NioConnection.java</code> Desc: 获取mina连接(单例)
 */
public class NioConnection
{

	private static final Logger logger = Logger.getLogger(NioConnection.class);

	public static Long DEFAULT_READ_OUT_TIME = 10000L;

	// 初始化一个NioSocketConnector的常量
	public static final NioSocketConnector ioConnector = new NioSocketConnector();

	// 初始化静态块
	static
	{
		logger.debug("初始化NioSocketConnector开始");

		// 设置NioSocketConnector的相关信息
		ioConnector.setConnectTimeoutMillis(DEFAULT_READ_OUT_TIME);
		ioConnector.getFilterChain().addFirst("logger", new LoggingFilter());
		ioConnector.getFilterChain().addLast("exceutor", new ExecutorFilter());
		TextLineCodecFactory textLineCodecFactory = new TextLineCodecFactory(Charset.forName("UTF-8"));
		textLineCodecFactory.setDecoderMaxLineLength(1000000);
		textLineCodecFactory.setEncoderMaxLineLength(1000000);
		ioConnector.getFilterChain().addLast("codec", new ProtocolCodecFilter(textLineCodecFactory));
		ioConnector.setHandler(new ClientHandler());// 此处可能不对
		ioConnector.getSessionConfig().setUseReadOperation(true);
		logger.debug("初始化NioSocketConnector结束");
	}

	/**
	 * 
	 * @Title: NioConnection
	 * @Description: 发送消息
	 * @param @param host
	 * @param @param port
	 * @param @param value
	 * @return @throws Exception
	 * @throws
	 */
	public static String sendMsg(String host, int port, String value) throws Exception
	{
		String retStr = "";

		try
		{
			String returnValue = null;
			ConnectFuture cf = ioConnector.connect(new InetSocketAddress(host, port));
			cf.awaitUninterruptibly();
			IoSession ioSession = cf.getSession();
			WriteFuture writeFuture = ioSession.write(value);
			writeFuture.awaitUninterruptibly(DEFAULT_READ_OUT_TIME, TimeUnit.MILLISECONDS);
			ReadFuture readFuture = ioSession.read();
			readFuture.awaitUninterruptibly(DEFAULT_READ_OUT_TIME, TimeUnit.MILLISECONDS);
			returnValue = (String) readFuture.getMessage();
			if (ioSession.isConnected())
			{
				ioSession.close(true);
			}

			retStr = new String(Base64.decode(returnValue == null ? "" : returnValue.toString()), "utf-8");

			logger.info("返回值:" + retStr);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		return retStr;

	}

	public NioConnection() {

	}

	public static void main(String[] args) throws Exception
	{
		String value = "TakeCustomers|5|100|" + "20141210" + "|" + "20150410";
		for (int i = 0; i < 1; i++)
		{
			NioConnection.sendMsg("192.168.188.10", 9002, value);
		}
	}
}

class ClientHandler extends IoHandlerAdapter
{
	private static final Logger logger = Logger.getLogger(ClientHandler.class);

	private void releaseSession(IoSession session) throws Exception
	{
		logger.debug("releaseSession");
		if (session.isConnected())
		{
			session.close(true);
		}
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception
	{
		logger.debug("sessionOpened");
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception
	{
		logger.debug("sessionClosed");
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status) throws Exception
	{
		logger.debug("sessionIdle");
		try
		{
			releaseSession(session);
		}
		catch (RuntimeIoException e)
		{
			logger.error(BusinessException.ACCESS_NUMBER_ERROR, e);
		}
	}

	@Override
	public void messageReceived(IoSession session, Object message) throws Exception
	{
		logger.debug("Receive Server message " + message);
		super.messageReceived(session, message);
		releaseSession(session);
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception
	{
		logger.info("exceptionCaught");
		logger.error(BusinessException.ACCESS_NUMBER_ERROR, cause);
		releaseSession(session);
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception
	{
		logger.debug("messageSent");
		super.messageSent(session, message);
	}
}

class ReturnFuture
{
	private String returnValue;

	public String getReturnValue()
	{
		return returnValue;
	}

	public void setReturnValue(String returnValue)
	{
		this.returnValue = returnValue;
	}
}

数据量打出来这些: VBOSS:<INFO>:2015-04-14 11:08:41,468[NioProcessor-3]>>CREATED VBOSS:<INFO>:2015-04-14 11:08:41,468[NioProcessor-3]>>OPENED VBOSS:<INFO>:2015-04-14 11:08:41,476[NioProcessor-3]>>SENT: HeapBuffer[pos=0 lim=0 cap=0: empty] VBOSS:<INFO>:2015-04-14 11:08:47,322[NioProcessor-3]>>RECEIVED: HeapBuffer[pos=0 lim=2048 cap=2048: 50 44 39 34 62 57 77 67 64 6D 56 79 63 32 6C 76...] VBOSS:<INFO>:2015-04-14 11:08:47,323[NioProcessor-3]>>RECEIVED: HeapBuffer[pos=0 lim=4096 cap=4096: 50 53 49 78 49 69 42 6A 63 6D 56 68 64 47 56 55...] VBOSS:<INFO>:2015-04-14 11:08:47,324[NioProcessor-3]>>RECEIVED: HeapBuffer[pos=0 lim=8192 cap=8192: 50 53 49 31 49 69 42 76 63 6D 52 6C 63 6C 4E 30...] VBOSS:<INFO>:2015-04-14 11:08:47,325[NioProcessor-3]>>RECEIVED: HeapBuffer[pos=0 lim=3040 cap=16384: 76 5A 45 69 49 48 4E 30 59 57 35 6B 59 58 4A 6B...] VBOSS:<INFO>:2015-04-14 11:08:47,326[NioProcessor-3]>>CLOSED VBOSS:<INFO>:2015-04-14 11:08:47,365[main]>>desc=[返回值:] 不知道啥意思。。
Inhibitory 2015-04-14
  • 打赏
  • 举报
回复
你们的传输的包设计的不好,按行读更是容易出问题:re = br.readLine() 自己设计一个包格式,例如:前4个字节表示消息的大小,然后跟消息的主体,所以包的大小就是 4 + 消息的大小。 接收端检测收到的消息先看前4个字节读出消息的大小,等到有这么多bytes后才读出消息。这种做法懂的不难,不懂得看上去一头雾水。 那么我推荐 1. 用Netty,Mina等成熟的工具来开发。 2. 用消息队列,如RabbitMQ开传消息。 这两种方式比自己写Socket好很多,消息的传达也不会丢失,学习都非常简单,1天的时间就能学会并使用。
lyw985 2015-04-14
  • 打赏
  • 举报
回复
记得flush一下
gloomyfish 2015-04-14
  • 打赏
  • 举报
回复
你readline的问题,最后可能没有加\r\n所以它一直以为没有最后结束 你可以直接读byte或者加上\r\n
thomashtq 2015-04-14
  • 打赏
  • 举报
回复
抓包分析下服务器端返回的数据是否完整。如果是HTTP协议,建议查看返回的 content-length和返回代码206表示只返回了部分。
淡定的峰哥 2015-04-14
  • 打赏
  • 举报
回复
像这种大字节的socket通讯,还可以做成分页发送,所以协议很重要
淡定的峰哥 2015-04-14
  • 打赏
  • 举报
回复
socket通讯最好是依据一个协议 就是内容由报文头+报文体 报文头可以用固定的几个字节来表示报文体的长度 读取了报文头的内容后得出报文体的长度 然后再读取那个长度的字节就可以
铁匠梁老师 2015-04-14
  • 打赏
  • 举报
回复
要断点调试,看看服务端是否发送完毕,或者接收端没有处理完收到的数据
rumlee 2015-04-14
  • 打赏
  • 举报
回复
将缓冲区设置大一点试试。
banditgao 2015-04-14
  • 打赏
  • 举报
回复
是本机的呀 本机 。服务器端确实没做什么特殊的约定,那到底怎么约定呢?
冥王之锤 2015-04-14
  • 打赏
  • 举报
回复
你这是本机调的结果,还远程调的结果。
lsongiu86 2015-04-14
  • 打赏
  • 举报
回复
引用 11 楼 banditgao 的回复:
使用MINA也需要约定 数据的格式吗? 比如 数据总长度+字节数 ?
对的,nio会有粘包发生的
banditgao 2015-04-14
  • 打赏
  • 举报
回复
使用MINA也需要约定 数据的格式吗? 比如 数据总长度+字节数 ?

62,634

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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