简体   繁体   中英

Java Socket connection without ServerSocket listening

This is the code where I connected two Socket without any ServerSocket :

package primary;

import java.awt.FlowLayout;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.*;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Client extends JFrame implements Runnable {
    private final String myName;
    private ServerSocket listener;
    private Socket connection1;
    private Socket connection2;
    private ObjectOutputStream output1;
    private ObjectOutputStream output2;
    private ObjectInputStream input1;
    private ObjectInputStream input2;
    private Object receiveObject;
    private Object1 sendObject1;
    private Object2 sendObject2;
    private final int[] myLocalPort;
    private final int[] connectionPort;
    private ExecutorService service;
    private Future<Boolean> future1;
    private Future<Boolean> future2;

    public Client(final String myName, int[] myLocalPort, int[] connectionPort) {
        super(myName);
        this.myName = myName;
        this.myLocalPort = myLocalPort;
        this.connectionPort = connectionPort;
        sendObject1 = new Object1("string1", "string2", myName);
        sendObject2 = new Object2("string1", 2.5, 2, true, myName);
        initComponents();
    }
    public void exe() {
        ExecutorService eService = Executors.newCachedThreadPool();
        eService.execute(this);
    }

    @Override
    public void run() {
        try {
                displayMessage("Attempting connection\n");
                try {
                    connection1  = new Socket(InetAddress.getByName("localhost"), connectionPort[0],
                            InetAddress.getByName("localhost"), myLocalPort[0]);
                    displayMessage(myName + " connection1\n");
                } catch (Exception e) {
                    displayMessage("failed1\n");
                    System.err.println("1" + myName + e.getMessage() + "\n");
                }
                try {
                    connection2  = new Socket(InetAddress.getByName("localhost"), connectionPort[1],
                            InetAddress.getByName("localhost"), myLocalPort[1]);
                    displayMessage(myName + " connection2\n");
                } catch (Exception e) {
                    displayMessage("failed2\n");
                    System.err.println("2" + myName + e.getMessage() + "\n");
                }
            displayMessage("Connected to: " + connection1.getInetAddress().getHostName() + "\n\tport: "
                    + connection1.getPort() + "\n\tlocal port: " + connection1.getLocalPort() + "\n"
                    + connection2.getInetAddress().getHostName() + "\n\tport: " + connection2.getPort()
                    + "\n\tlocal port: " + connection2.getLocalPort() + "\n\n");
            output1 = new ObjectOutputStream(connection1.getOutputStream());
            output1.flush();
            output2 = new ObjectOutputStream(connection2.getOutputStream());
            output2.flush();
            input1 = new ObjectInputStream(connection1.getInputStream());
            input2 = new ObjectInputStream(connection2.getInputStream());
            displayMessage("Got I/O stream\n");
            setTextFieldEditable(true);
            service = Executors.newFixedThreadPool(2);
            future1 = service.submit(
                    new Callable<Boolean>() {

                @Override
                public Boolean call() throws Exception {
                    try {
                        processConnection(input1);
                        displayMessage("input1 finished");
                    } catch (IOException e) {
                        displayMessage("blah");
                    }
                    return true;
                }
            });
            future2 = service.submit(
                    new Callable<Boolean>() {

                @Override
                public Boolean call() throws Exception {
                    try {
                        processConnection(input2);
                        displayMessage("input2 finished");
                    } catch (IOException e) {
                        displayMessage("foo");
                    }
                    return true;
                }
            });
        } catch (UnknownHostException e) {
            displayMessage("UnknownHostException\n");
            e.printStackTrace();
        } catch (EOFException e) {
            displayMessage("EOFException\n");
            e.printStackTrace();
        } catch (IOException e) {
            displayMessage("IOException\n");
            e.printStackTrace();
        } catch(NullPointerException e) {
            System.err.println("asdf " + e.getMessage());
        } finally {
            try {
                displayMessage("i'm here\n");
                if((future1 != null && future1.get()) && (future2 != null && future2.get())) {
                    displayMessage(future1.get() + " " + future2.get() + "\n");
                    displayMessage("Closing Connection\n");
                    setTextFieldEditable(false);
                    if(!connection1.isClosed()) {
                        output1.close();
                        input1.close();
                        connection1.close();
                    }
                    if(!connection2.isClosed()) {
                        output2.close();
                        input2.close();
                        connection2.close();
                    }
                    displayMessage("connection closed\n");
                }
            } catch (IOException e) {
                displayMessage("IOException on closing");
            } catch (InterruptedException e) {
                displayMessage("InterruptedException on closing");
            } catch (ExecutionException e) {
                displayMessage("ExecutionException on closing");
            }
        }
    }//method run ends
    private void processConnection(ObjectInputStream input) throws IOException {
        String message = "";
        do {
            try {
                receiveObject = input.readObject();
                if(receiveObject instanceof String) {
                    message = (String) receiveObject;
                    displayMessage(message + "\n");
                } else if (receiveObject instanceof Object1) {
                    Object1 receiveObject1 = (Object1) receiveObject;
                    displayMessage(receiveObject1.getString1() + " " + receiveObject1.getString2()
                            + " " + receiveObject1.toString() + "\n");
                } else if (receiveObject instanceof Object2) {
                    Object2 receiveObject2 = (Object2) receiveObject;
                    displayMessage(receiveObject2.getString1() + " " + receiveObject2.getD()
                            + " " + receiveObject2.getI() + " " + receiveObject2.toString() + "\n");
                }
            } catch (ClassNotFoundException e) {
                displayMessage("Unknown object type received.\n");
            }
            displayMessage(Boolean.toString(message.equals("terminate\n")));
        } while(!message.equals("terminate"));
        displayMessage("finished\n");
        input = null;
    }

    private void initComponents() {

        dataField = new javax.swing.JTextField();
        sendButton1 = new javax.swing.JButton();
        sendButton2 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        resultArea = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setLayout(new FlowLayout());
        dataField.setEditable(false);
        dataField.setColumns(20);
        dataField.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dataFieldActionPerformed(evt);
            }
        });

        sendButton1.setText("Send Object 1");
        sendButton1.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButton1ActionPerformed(evt);
            }
        });

        sendButton2.setText("Send Object 2");
        sendButton2.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButton2ActionPerformed(evt);
            }
        });

        resultArea.setColumns(25);
        resultArea.setRows(15);
        resultArea.setEditable(false);
        resultArea.setRows(5);
        jScrollPane1.setViewportView(resultArea);

        add(dataField);
        add(sendButton1);
        add(sendButton2);
        add(jScrollPane1);
        pack();
    }
    private void dataFieldActionPerformed(java.awt.event.ActionEvent evt) {                                          
        // TODO add your handling code here:
        sendData(evt.getActionCommand());
        dataField.setText("");
    }                                         

    private void sendButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                            
        // TODO add your handling code here:
        sendData(sendObject1);
    }                                           

    private void sendButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                            
        // TODO add your handling code here:
        sendData(sendObject2);
    }                                  

    private void displayMessage(final String messageToDisplay) {
        SwingUtilities.invokeLater(
                new Runnable() {
            @Override
                    public void run() {
                        resultArea.append(messageToDisplay);
                    }
                });
    }
    private void setTextFieldEditable(final boolean editable) {
        SwingUtilities.invokeLater(
                new Runnable() {

            @Override
            public void run() {
                dataField.setEditable(editable);
            }
        });
    }
    private void sendData(final Object object) {
        try {
            output1.writeObject(object);
            output1.flush();
            output2.writeObject(object);
            output2.flush();
            displayMessage(myName + ": " + object.toString() + "\n");
        } catch (IOException e) {
            displayMessage("Error writing object\n");
        }
    }

    private javax.swing.JTextField dataField;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea resultArea;
    private javax.swing.JButton sendButton1;
    private javax.swing.JButton sendButton2;
}

And the main:

    package primary;

import javax.swing.SwingUtilities;


public class Main {
    private static Object locker;

    public static void main(String[] args) {
        locker = new Object();
        final int[][] a = new int[6][];
        final int[][] b = new int[6][];
        final int[][] c;
        a[0] = new int[] {12340, 12341};
        a[1] = new int[] {12342, 12344};
        a[2] = new int[] {12342, 12343};
        a[3] = new int[] {12340, 12345};
        a[4] = new int[] {12344, 12345};
        a[5] = new int[] {12341, 12343};

        b[0] = new int[] {22340, 22341};
        b[1] = new int[] {22342, 22344};
        b[2] = new int[] {22342, 22343};
        b[3] = new int[] {22340, 22345};
        b[4] = new int[] {22344, 22345};
        b[5] = new int[] {22341, 22343};

        c = a;
        SwingUtilities.invokeLater(
                new Runnable() {

            @Override
            public void run() {
                Client client1 = new Client("client1", c[0], c[1]);
                client1.exe();
                client1.setLocation(0, 0);
                client1.setVisible(true);
            }
        });
        SwingUtilities.invokeLater(
                new Runnable() {

            @Override
            public void run() {
                Client client2 = new Client("client2", c[2], c[3]);
                client2.exe();
                client2.setLocation(0, 200);
                client2.setVisible(true);
            }
        });
        SwingUtilities.invokeLater(
                new Runnable() {

            @Override
            public void run() {
                Client client3 = new Client("client3", c[4], c[5]);
                client3.exe();
                client3.setLocation(0, 400);
                client3.setVisible(true);

            }
        });
    }
}

Here Object1 and Object2 are just two Serializable Objects. All the sockets connect perfectly, it seems. If I exit the system without calling the close() methods for the sockets and their input, output streams and re-run, it works fine still. But if I exit system after making sure that the close() methods are called, and I re-run again, I get this: 1client2Address already in use: connect

1client3Address already in use: connect

2client3Address already in use: connect

asdf null
1client1Connection refused: connect

2client2Connection refused: connect

asdf null
2client1Connection refused: connect

asdf null

I re-run again and again, I keep getting this, unless, I wait a certain amount of time and re-run again, it works just fine as the first time. Why something like this happening? why it's taking so much time if I close the socket and not when not closing them? Are they really closing or just merely connecting the existing connection when I do not close the sockets? But when using ServerSocket it doesn't seem to happen in cases when I close. What is actually going on?

Another question, ServerSocket supposedly hands out its end of Socket connection to a localport other than on which it is listening. If it is true, why do I get the listening localport when I call Socket.getLocalPort(), for all the socket it accepted?

Don't use the 3rd and 4th parameters when creating the Socket . There is no genuine need to specify the local address, short of a VPN, and no genuine need to specify a local port at all other than as a figment of your netadmin's imagination.

ServerSocket supposedly hands out its end of Socket connection to a localport other than on which it is listening.

No it doesn't. All the accepted sockets use the same local port as the listening port.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM