开发者

Java, ports, sockets, piping a connection through a programme

开发者 https://www.devze.com 2023-04-08 11:16 出处:网络
I need to pipe a connection between two programs on different devices in my LAN. I.e., I have device A that should connect to device B:portX in my LAN. The problem is that i cannot connect them to eac

I need to pipe a connection between two programs on different devices in my LAN. I.e., I have device A that should connect to device B:portX in my LAN. The problem is that i cannot connect them to each other directly. What i have to do is to make device A connect to a server, and have that server connect to device B. On my server i listen to the port "portX", and when i get the connection, i connect to device B on the same port. Then i have to channel the data from A to B through the server, but for some reason device B doesn't do what it should do when it receives the data (commands) from A.

How can I do this?

Here is how i have been trying to do this:

public class Main {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8000);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 8000.");
            System.exit(1);
        }
        Socket clientSocket = null;
        try {
            clientSocket = serverSocket.accept();
            System.err.println("connection accepted");
        } catch (IOException e) {
            System.err.println("Accept failed.");
            System.exit(1);
        }
        Socket remoteSocket = null;
        try {
            remoteSocket = new Socket("192.168.1.74", 8000);
        } catch (Exception e) {
            System.out.println("Failed to connect to device B");
        }
        PrintWriter remoteOut = new PrintWriter(remoteSocket.getOutputStream(),
                true);
        BufferedReader remoteIn = new BufferedReader(new InputStreamReader(
                remoteSocket.getInputStream()));
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(
                clientSocket.getInputStream()));
        String inputLine;
        System.out.println("Hi, we are before the while");
        int inputChar = 0;
        while ((inputChar = in.read()) >= 0) {
            remoteOut.println(inputChar);
            System.out.println(inputChar);
        }
        System.out.println("We are after the while");
        out.close();
        in.close();
        remoteIn.close();
        remoteOut.close();
        clientSocket.close();
        serv开发者_开发问答erSocket.close();
        remoteSocket.close();
    }
}

Thanks in advance, Timofey


I created a version that uses the NIO channels. The benefit of this approach is that you can use a single Thread to manage what is coming in from multiple sources. I don't need to necessarily know what the protocol is between the two services because we are just copying bytes. If you wanted to just use plain old sockets, you would need to use a mutex and 2 threads to read/write data between the two sockets (sockets are not thread-safe).

NOTE: There may be better ways to handle the error conditions than just dropping the connections and creating new ones.

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Set;

/**
 * Socket Gateway for SO Question 7528528
 * User: jhawk28
 * Date: 9/26/11
 * Time: 9:03 PM
 * <p/>
 * http://stackoverflow.com/questions/7528528/java-ports-sockets-piping-a-connection-through-a-programme
 */
public class Gateway
{
  public static void main(String[] args) throws IOException
  {
    // Set up Server Socket and bind to the port 8000
    ServerSocketChannel server = ServerSocketChannel.open();
    SocketAddress endpoint = new InetSocketAddress(8000);
    server.socket().bind(endpoint);

    server.configureBlocking(false);

    // Set up selector so we can run with a single thread but multiplex between 2 channels
    Selector selector = Selector.open();
    server.register(selector, SelectionKey.OP_ACCEPT);


    ByteBuffer buffer = ByteBuffer.allocate(1024);

    while (true)
    {
      // block until data comes in
      selector.select();

      Set<SelectionKey> keys = selector.selectedKeys();

      for (SelectionKey key : keys)
      {
        if (!key.isValid())
        {
          // not valid or writable so skip
          continue;
        }

        if (key.isAcceptable())
        {
          // Accept socket channel for client connection
          ServerSocketChannel channel = (ServerSocketChannel) key.channel();
          SocketChannel accept = channel.accept();
          setupConnection(selector, accept);
        }
        else if (key.isReadable())
        {
          try
          {
            // Read into the buffer from the socket and then write the buffer into the attached socket.
            SocketChannel recv = (SocketChannel) key.channel();
            SocketChannel send = (SocketChannel) key.attachment();
            recv.read(buffer);
            buffer.flip();
            send.write(buffer);
            buffer.rewind();
          } catch (IOException e)
          {
            e.printStackTrace();

            // Close sockets
            if (key.channel() != null)
              key.channel().close();
            if (key.attachment() != null)
              ((SocketChannel) key.attachment()).close();
          }
        }
      }

      // Clear keys for next select
      keys.clear();
    }
  }

  public static void setupConnection(Selector selector, SocketChannel client) throws IOException
  {
    // Connect to the remote server
    SocketAddress address = new InetSocketAddress("192.168.1.74", 8000);
    SocketChannel remote = SocketChannel.open(address);

    // Make sockets non-blocking (should be better performance)
    client.configureBlocking(false);
    remote.configureBlocking(false);

    client.register(selector, SelectionKey.OP_READ, remote);
    remote.register(selector, SelectionKey.OP_READ, client);
  }
}


Your problem is that you are using a PrintWriter as your forwarding mechanism. You read in a char and then write out the char + a newline. Try switching it to a remoteOut.print(inputChar);

A better solution would just read the character and then write out the character (you can use a BufferedWriter). commons-io already has copy methods that do this sort of thing in IOUtils

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号