Java中的Client Server通信:如何区分套接字

时间:2016-01-13 08:49:52

标签: java sockets server client serversocket

我现在正在使用Socket和ServerSocket对象处理Java中的客户端 - 服务器通信。 一旦服务器初始化,它就会通过来自ServerSocket类的accept()方法与新客户端保持一致;我立即提供将此套接字放在服务器上的客户端映射中:   - keys:ClientNode(Socket s,CommunicationChannels channels);   - values:Info(); (CommunicationChannels包含来自socket的ObjectOutputStream和ObjectInputStream; Info包含有关客户端的一些信息,如用户名,消息等。)。

鉴于此,在开头,套接字除了套接字本身之外在客户端上没有任何其他信息,首先在地图上插入是map.put(ClientNode,null)。之后我将填写“价值”字段。

现在,在Client类中,我将初始化一个Socket(“127.0.0.1”,13001),即带有环回地址和门13001.一旦初始化了通信通道,客户端就连接到服务器。

客户端启动后,他通过RMI(存根)库获取服务器的远程副本,服务器使register()方法可用:它允许使用此方法(从客户端)写入请求的信息地图。

客户端如何返回已在服务器上注册的套接字?坦率地说,我认为来自ServerSocket的accept()方法可以将在启动客户端上建立的套接字带回服务器,即使用新的Socket(“127.0.0.1”,13001),但在我看来,这不是发生。

在这里你可以找到部分代码,这样你就可以更好地理解我在说什么。我已经考虑了一些我需要与你分享的东西。

public class Server implements Runnable, RemoteServices {
...
private Map<ClientNode, Info> map = new HashMap<ClientNode, Info>();
...
public void run() {
    ServerSocket ss = null;
    try {
        ss = new ServerSocket();
        while (true) {
            if (!ss.isBound()) {
                ss.bind(new InetSocketAddress(ipServer, port));
            }
            Socket client = ss.accept();
            CommunicationChannels channels = new CommunicationChannels(new ObjectOutputStream(client.getOutputStream()), new ObjectInputStream(client.getInputStream()));
            map.put(new ClientNode(client, channels), null);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// RemoteServices implementa Remote e mette a disposizione register()
public void register(Info info) throws RemoteException {
        // TODO         
}


public class Client implements Runnable {
...
...

@Override
public void run() {

        Socket client = null;

        try {
            client = new Socket(ipServer, port);

                out = new ObjectOutputStream(client.getOutputStream());
            in = new ObjectInputStream(client.getInputStream());

                        Registry registry = LocateRegistry.getRegistry("127.0.0.1");
            stub = (RemoteServices) registry.lookup("remoteObject");

                       Info info = new Info();
            info.setID(getID());
            info.setUsername("Giordano");

                        stub.register(info);
        } catch (IOException e) {
            System.err.println("Spiacente: il server ha terminato l'esecuzione.");
            e.printStackTrace();
        } catch (NotBoundException e) {
            e.printStackTrace();
        } 
    }
}

说明:

  1. 我没有包含某些类的代码,因为我觉得它是多余的;例如,“info”类只是一些字段的“getter and setter”系列; CommunicationChannels类表示客户端的通信通道,直接从套接字等获取。
  2. 服务器在accept()之后,不会实例化任何与客户端通信的线程,因为之后必须进行通信。但是,如果有办法用通信线程解决我的问题,我会找到一种解决方法。
  3. 我的问题始于需要在不使用更多PC的情况下与服务器进行交互2个客户端;因此,所有客户端都将具有IP环回,因此我无法使用IP地址作为区分两个套接字,否则我已经解决了它。 换句话说,我知道socket.getInetAddress()。getHostAddress()方法可以帮助我区分两个套接字,但是如果我在同一台PC上初始化两个客户端,我必须使用环回地址,并且该方法总是返回“127.0 .0.1" 。
  4. 即使在签名中,register()方法也显然不完整;一旦理解了如何通过Serializable识别对象(如hashcode())比较服务器套接字和客户端,可能我可能会把它放在方法的参数中,这样你就可以轻松进行比较。
  5. 最后,main()方法:

    public static void main(String[] args) {
            Server server = new Server("127.0.0.1", 13001);
            RemoteServices stub;
            try {
                stub = (RemoteServices) UnicastRemoteObject.exportObject(server, 0);
                Registry registry = LocateRegistry.getRegistry();
                registry.bind("remoteObject", stub);
                (new Thread(server)).start();
            } catch (RemoteException e) {
                System.err.println("Verificare l'apertura dei registri");
            } catch (AlreadyBoundException e) {
                System.err.println("Server già attivo. Controllare che i registri siano chiusi correttamente.");
            }
        }
    
    public static void main(String[] args) {        Client client = new Client("127.0.0.1", 13001);
            new Thread(client).start();
        }
    

    我真的希望一切都清楚,你可以帮助我。

0 个答案:

没有答案