为了把问题说明清楚,把我写的代码贴出来(共三部分),请大家为我解答:
一个是Socket的服务端(用Java编写的),另一个是Socket的客户端(这个Socket客户端C++写的)。Socket的服务端可以向Socket的客户端发送信令,这个大家都知道,但现在Socket的服务端必须要抛出一个多线程便于一直接收Socket客户端发过来的信令,不然若客户端有什么请求,我就不知道了.
注:客户端必须先向服务端链接,这样服务端才得到一个链接(Socket).
下面详细说明一下:
服务器先起来,然后客户端向服务器端建立一个连接,服务器端收到连接后,用一个全局变量保存起来;
在这里保存起来有两个目的:1.让服务端保持这个链接,不需要以后重新再链接,2.可以在其它方法里(比如C部分)利用这个保存的Socket向客户端发信。
各个部分的含义:
A部分,服务器端收到客户端的连接,并将这个链接(socket)保存起来,注意,服务器端收到连接后并不是立即给客户端发送信令,具体向客户端发信的是通过C部分实现的;然后new SocketServerThread(socket).start(),便于可以一直(随时)接收客户端的信令。
B部分,接收客户端的信令。因为要可以随时接收不同客户端的信令(业务要求),所以要用到多线程。当通过C部分向客户端发送信令后(送信的内容是xml体,里面包含sessionid等其它数据),那么只能(因为要随时接收不同客户端的信令,所以用一个while循环)通过这个多线程接收了。先发送,再等待返回。那当多线程收到客户端信令的返回时,怎么通知C部分(已经收到返回了)呢?所以就在多线程里用一个全局Map把这个结果保存起来,便于C部分可以通过轮询这个变量,已得知客户端已返回。那怎么确定信息是C的哪次发信返回的结果呢?就是通过sessionid的值来确定的(下面有说明),即我每次在送信前记住这个sessionid,在收信时就找对应的结果(结果也是一个xml体)。每次送信的sessionid都不相同。这是一个瓶颈,尤其在多线程里,这正是我提问题的原因所在。
C部分,利用全局Map保存的socket向客户端发送信令;轮询这个变量,通过sessionid查找对应的结果,看多线程(B部分)是否收到客户端信令的返回。
这是一个会议系统,只要创建会议(是通过用户在页面点击来调用C部分的方法来发起通信的),都会送信。
这是每次送信的内容,是一个xml体,即:
- Java code
<iabi> <cmd id= "3000 " sessionid= "1412412341 "> <confid> 88888888 </confid> </cmd> </iabi>
A部分:
- Java code
public class SocketServer extends Thread { private Logger log= Logger.getLogger(SocketServer.class.getName()); private ServerSocket serverSocket; private int listenPort =8188; public SocketServer(int listenPort) { this.listenPort = listenPort; } public static Map socketMap=new HashMap();//保存socket的HashMap public static Map resultMap=new HashMap();//保存发出通信的的返回结果Map private Socket socket; private boolean isLoop= false; public void run(){ isLoop=true; try { serverSocket= new ServerSocket(listenPort); log.info("Starting listen......"); String ccsIp=""; CcsInfo ccsInfo=null; while(isLoop){ socket = serverSocket.accept(); log.info("Listening->RemoteSocketAddress:"+socket.getRemoteSocketAddress()+" InetAddress:"+socket.getInetAddress()); ccsIp=socket.getRemoteSocketAddress().toString().trim(); ccsIp=ccsIp.substring(1,ccsIp.indexOf(":")); log.info("RemoteSocketIp:"+ccsIp); socketMap.put(ccsIp,socket); log.info("Having listen the IP:" +ccsIp+" The ccsID:"+ccsInfo.getCcsId()); new SocketServerThread(socket).start(); } } catch (Exception e) { isLoop = false; log.error(" "+e); } } }
B部分:
- Java code
public class SocketServerThread extends Thread { private Logger log= Logger.getLogger(SocketServerThread.class.getName()); private Socket socket; private int result; private boolean isLoop; ByteArrayOutputStream buf = new ByteArrayOutputStream(); public SocketServerThread(Socket s){ this.socket = s; } public void run(){ isLoop=true; result=0; InputStream in=null; try { in =new BufferedInputStream(socket.getInputStream()); } catch (IOException e){ log.error("The CCS "+socket.getRemoteSocketAddress()+" is unusual:"+e); } int readLen=1024; int count=0; byte[] readBuf=new byte[readLen]; while(true&&isLoop){ count=0; try{ do{ count=in.read(readBuf); if(count==-1){ isLoop=false; throw new IOException("The receive data length is not right"); } buf.write(readBuf,0,count); }while (count==readLen); log.info("Receive:"+new String(buf.toByteArray())); }catch(IOException ex){ log.error("The CCS "+socket.getRemoteSocketAddress()+" correspondence is unusual:"+ex); } //收到的结果是一个xml体,然后解析出sessionid和通信的结果result SocketServer.resultMap.put(sessionid,result);//保存返回结果 } }}