日期:2014-05-20  浏览次数:20785 次

棘手的Socket问题,涉及到多线程。请大家帮忙!
为了把问题说明清楚,把我写的代码贴出来(共三部分),请大家为我解答:

一个是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);//保存返回结果
               }
      }
}