http://wuhui0915.blog.163.com/blog/static/2186455320109292221272/
Socket 的粘包问题我这里就不多说了,网上到处是,本人也碰到了这个问题,在网上找了一下资料,研究了一下,终于解决了这个问题,以下是我的处理方式,我用了 Apache mina 2.0.1 自带的PrefixedStringCodecFactory这个数据编解码器,它的处理方式是包含一个发送数据的长度,然后根据长度来得到你发送的数据包,这样就不会出现粘包的问题。
如图所示:

发送的时候是这样,接收的时候也是这样,所以要在客户端自己做处理
开发环境:
MyEclipse6.5 + JDK1.6.11 + FlexBuilder 3
准备工作:
1.去 http://www.apache.org 下载 apache-mina-2.0.1-bin;
2.建立一个 javaProject 将 apache-mina-2.0.1\dist\mina-core-2.0.1.jar 和 apache-mina-2.0.1\lib\slf4j-api-1.5.11.jar 导入;
3.去 http://www.slf4j.org 下载 slf4j-1.5.11;
4.将 slf4j-1.5.11\slf4j-simple-1.5.11.jar 导入 (这个jar包是必须的,否则运行的时候会报错)。
jar包全部导入后如图

服务端代码:
代码结构(一共3个类,用来测试用的,至于接收到数据后你怎么处理,你自己在加):
MinaServer.java
MinaSessionHandle.java
MinaSocketTest.java
MinaServer.java
package com.derek.socket.mina;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.prefixedstring.PrefixedStringCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class MinaServer {
private static final int PORT = 12727;
final IoAcceptor acceptor = new NioSocketAcceptor();
public MinaServer() {
acceptor.setHandler(new MinaSessionHandle());
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new PrefixedStringCodecFactory(Charset.forName("UTF-8"))));
try {
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Game Socket Server Started...");
} catch (IOException e) {
e.printStackTrace();
}
}
public void shutdown() {
acceptor.unbind();
acceptor.dispose();
}
}
MinaSessionHandle.java
package com.derek.socket.mina;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
public class MinaSessionHandle extends IoHandlerAdapter {
@Override
public void sessionCreated(IoSession session) throws Exception {
System.out.println("the new session is connecting");
}
/**
* 注意:这里是 PrefixedStringCodecFactory 已经处理过的数据,只接收内容部分,数据长度部分将被过滤掉
*/
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
try {
System.out.println("****"+message+"****");
// TODO 这里定义你自己的方法
//注意:这里发送最后也是通过PrefixedStringCodecFactory 处理过后的数据(包括文件数据长度和内容两部分)
session.write(message.toString()); //发送回客服端(测试用)
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
System.out.println("客户端 " + session.getRemoteAddress() + " 关闭了连接");
session.close(false);
}
}
MinaSocketTest.java
package com.derek.socket.mina;
public class MinaSocketTest extends Thread{
public void run () {
new MinaServer();
}
public static void main(String args[]){
MinaSocketTest test = new MinaSocketTest();
test.start();
}
}
客服端:
建一个测试的类就行
SocketTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
<mx:Script>
<![CDATA[
import flash.net.Socket;
import com.adobe.serialization.json.JSON;
private var socket:Socket;
private var socketlen:int = 0;
private function init():void
{
socket = new Socket();
//连接 Socket
socket.connect("127.0.0.1",12727);
//注册 Socket连接事件
socket.addEventListener(Event.CONNECT,socketConnect);
//注册 Socket关闭事件
socket.addEventListener(Event.CLOSE,socketClose);
//注册 安全错误事件
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,securityError);
//注册 IO错误事件
socket.addEventListener(IOErrorEvent.IO_ERROR,socketIOError);
//注册 处理Socket接收数据事件
socket.addEventListener(ProgressEvent.SOCKET_DATA,socketData);
}
//连接建立
private function socketConnect(event:Event):void{
/**
* 向服务器发送数据
*/
this.sendData("-------已经建立连接");
}
private function sendAllData():void{
for (var i:int=0;i<100;i++)
{
this.sendData("IUUUIIIOIU");
this.sendData("3399TT999");
this.sendData("091567");
this.sendData("3odjs9r000sfdjkfjsldwe34");
}
}
//连接关闭
private function socketClose(event:Event):void{
trace("----链接关闭");
socket.close();
socket = null;
}
//连接关闭
private function thisSocketClose():void{
trace("--this--连接关闭--");
socket.close();
socket = null;
}
//安全错误
private function securityError(event:SecurityErrorEvent):void{
trace("----安全错误");
socket.close();
socket = null;
}
//IO错误
private function socketIOError(event:Event):void{
trace("----IO错误");
socket.close();
socket = null;
}
//发送数据
private function sendData(data:String):void{
if(socket == null) return;
if(data==null||data.length==0) return;
var byte:ByteArray = new ByteArray();
byte.writeUTFBytes(data);
//下面注意:
socket.writeInt(byte.length); //先写入数据的长度
socket.writeBytes(byte); //再写入内容
socket.flush();
}
//接收数据
private function socketData(event:ProgressEvent):void{
try{
while(true){
//先读取数据长度,再根据长度读取数据
if (socketlen == 0)
{
if (socket.bytesAvailable < 4) return;
socketlen = socket.readInt();
trace("****"+socketlen+"****");
}
if (socket.bytesAvailable < socketlen) return;
var msg:String = socket.readUTFBytes(socketlen);
socketlen=0;
trace("****"+msg+"****");
// TODO 这里定义你自己的方法
}
}catch(e:Error){
trace(e.message);
}
}
]]>
</mx:Script>
<mx:Button x="211" y="250" label="发送" click="sendAllData();"/>
<mx:Button x="291" y="250" label="关闭" click="thisSocketClose();"/>
</mx:Application>