【问题标题】:Combine two servers to one? - Java socket将两台服务器合二为一? - Java 套接字
【发布时间】:2015-10-29 08:50:03
【问题描述】:

所以我一直在尝试制作一个程序。该程序有点基本。我想制作一个发送图片的聊天程序。所以现在的问题是我现在有两台服务器和两个客户端。一个用于聊天,一个用于图片。我想将它们组合到一台服务器上,以使代码越来越有用,但我不知道它是否可能。否则我需要一个提示方法如何继续前进,因为现在我卡住了。所以我的服务器看起来像这样。有可能吗?

服务器聊天:

public Server(int port) {
        this(port, null);
    }

    public Server(int port, ServerGUI sg) {
        // GUI or not
        this.sg = sg;
        // the port
        this.port = port;
        // to display hh:mm:ss
        sdf = new SimpleDateFormat("HH:mm:ss");
        // ArrayList for the Client list
        al = new ArrayList<ClientThread>();
    }

    public void start() {
        keepGoing = true;
        /* create socket server and wait for connection requests */
        try 
        {
            // the socket used by the server
            ServerSocket serverSocket = new ServerSocket(port);

            // infinite loop to wait for connections
            while(keepGoing) 
            {
                // format message saying we are waiting
                display("Server waiting for Clients on port " + port + ".");

                Socket socket = serverSocket.accept();      // accept connection
                // if I was asked to stop
                if(!keepGoing)
                    break;
                ClientThread t = new ClientThread(socket);  // make a thread of it
                al.add(t);                                  // save it in the ArrayList
                t.start();
            }
            // I was asked to stop
            try {
                serverSocket.close();
                for(int i = 0; i < al.size(); ++i) {
                    ClientThread tc = al.get(i);
                    try {
                    tc.sInput.close();
                    tc.sOutput.close();
                    tc.socket.close();
                    }
                    catch(IOException ioE) {
                        // not much I can do
                    }
                }
            }
            catch(Exception e) {
                display("Exception closing the server and clients: " + e);
            }
        }
        // something went bad
        catch (IOException e) {
            String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
            display(msg);
        }
    }       

class ClientThread extends Thread {
    // the socket where to listen/talk
    Socket socket;
    ObjectInputStream sInput;
    ObjectOutputStream sOutput;
    // my unique id (easier for deconnection)
    int id;
    // the Username of the Client
    String username;
    // the only type of message a will receive
    Message cm;
    // the date I connect
    String date;

    // Constructore
    ClientThread(Socket socket) {
        // a unique id
        id = ++uniqueId;
        this.socket = socket;
        /* Creating both Data Stream */
        System.out.println("Thread trying to create Object Input/Output Streams");
        try
        {
            // create output first
            sOutput = new ObjectOutputStream(socket.getOutputStream());
            sInput  = new ObjectInputStream(socket.getInputStream());
            // read the username
            username = (String) sInput.readObject();
            display(username + " just connected.");
        }
        catch (IOException e) {
            display("Exception creating new Input/output Streams: " + e);
            return;
        }
        // have to catch ClassNotFoundException
        // but I read a String, I am sure it will work
        catch (ClassNotFoundException e) {
        }
        date = new Date().toString() + "\n";
    }

图片服务器

public class GreetingServer {

  public final static int SOCKET_PORT = 13267;  // you may change this
  public final static String FILE_TO_SEND = "C:/Users/Barry/Desktop/Duck.jpg";  // you may change this

  public static void main (String [] args ) throws IOException {
    FileInputStream fis = null;
    BufferedInputStream bis = null;
    OutputStream os = null;
    ServerSocket servsock = null;
    Socket sock = null;
    try {
      servsock = new ServerSocket(SOCKET_PORT);
      while (true) {
        System.out.println("Waiting...");
        try {
          sock = servsock.accept();
          System.out.println("Accepted connection : " + sock);
          // send file
          File myFile = new File (FILE_TO_SEND);
          byte [] mybytearray  = new byte [(int)myFile.length()];
          fis = new FileInputStream(myFile);
          bis = new BufferedInputStream(fis);
          bis.read(mybytearray,0,mybytearray.length);
          os = sock.getOutputStream();
          System.out.println("Sending " + FILE_TO_SEND + "(" + mybytearray.length + " bytes)");
          os.write(mybytearray,0,mybytearray.length);
          os.flush();
          System.out.println("Done.");
        }
        finally {
          if (bis != null) bis.close();
          if (os != null) os.close();
          if (sock!=null) sock.close();
        }
      }
    }
    finally {
      if (servsock != null) servsock.close();
    }
  }
}

【问题讨论】:

  • 是的,这是可能的。端口号将不同。即聊天服务器端口:13266 和图片服务器端口:13267
  • 嗯。但有可能这样做吗?有一个聊天客户端,通过按下一个名为“图片”的按钮,您将能够向聊天客户端发送您想要的图片?如是。那怎么办^?

标签: java sockets server


【解决方案1】:

要将两种数据放在同一个套接字上,您需要以某种方式区分这两种数据。由于无论如何您都在使用对象输入/输出流,因此使用这两个类似乎是一种区分的好方法。使用 isAssignableFrom 找出每个对象是哪一个。

public static class ChatText implements Serializable {

    private String text;

    /**
     * Get the value of text
     *
     * @return the value of text
     */
    public String getText() {
        return text;
    }

    /**
     * Set the value of text
     *
     * @param text new value of text
     */
    public void setText(String text) {
        this.text = text;
    }

}

...

public static class PictureData implements Serializable {

    private byte[] data;

    /**
     * Get the value of data
     *
     * @return the value of data
     */
    public byte[] getData() {
        return data;
    }

    /**
     * Set the value of data
     *
     * @param data new value of data
     */
    public void setData(byte[] data) {
        this.data = data;
    }
}

...

public static void main(String[] args) {
    try {
        // Server implemented here
        ExecutorService es = Executors.newFixedThreadPool(4);
        ServerSocket ss = new ServerSocket(1234);
        es.submit(() -> {
            while (true) {
                Socket s = ss.accept();
                es.submit(() -> {
                    ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                    while (true) {
                        Object o = ois.readObject();
                        if (PictureData.class.isAssignableFrom(o.getClass())) {
                            PictureData pd = (PictureData) o;
                            System.out.println("got picture:" + Arrays.toString(pd.getData()));
                            // Do something with picture here.
                        } else if (ChatText.class.isAssignableFrom(o.getClass())) {
                            ChatText ct = (ChatText) o;
                            System.out.println("got text:" + ct.getText());
                            // Do something with chat here.
                        }
                    }
                });
            }
        });

        // Client implemented here, just for Testing
        Socket s = new Socket("localhost", 1234);
        ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
        ChatText ct = new ChatText();
        ct.setText("first chat");
        oos.writeObject(ct);

        //In a real client, the next three lines would be in a separate 
        // class/function attached to some event handler.
        PictureData pd = new PictureData();
        pd.setData(new byte[]{1, 2, 3, 4});
        oos.writeObject(pd);

        Thread.sleep(2000); // ugly hack to make sure server doesn't close too early, for testing only
        es.shutdownNow();
        s.close();
        ss.close();

    } catch (IOException | InterruptedException ex) {
        ex.printStackTrace();
    }

}

真正的客户会将我标记的部分放在 main 中,并从某个事件处理程序中运行它。更像这样:

public class MyClient extends JFrame {

    MyClient(String host, int port) {
        try {
            Socket s= new Socket(host,port);
            JButton myButton = new JButton("Send Picture");
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            myButton.addActionListener(e -> {
                try { 
                    // Copy of code from previous example.
                    PictureData pd = new PictureData();
                    pd.setData(new byte[]{1, 2, 3, 4});
                    oos.writeObject(pd);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            });
            add(myButton);
            pack();
            setVisible(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(() -> new MyClient("localhost",1234));
    }
}

【讨论】:

  • 我想的更像。有一个自己的图片发送类,但我真的不知道如何。我的想法是在聊天服务器上添加一些东西,这样当我在我的 GUI 上按下“图片按钮”时,同一个服务器将连接到同一个类上。它将采用该类的算法。所以我真的不必把它混在一个班级里。那有可能吗? @WillShackleford
  • 非常感谢您!让它工作。或者差不多。现在是 JtextArea 的另一个问题。
猜你喜欢
  • 2013-09-06
  • 1970-01-01
  • 2013-02-11
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-20
相关资源
最近更新 更多