简体   繁体   English

如何在覆盖的 run() 方法中使用现有对象?

[英]How to use existing Objects in an overwritten run() Method?

I'm a beginner in programming and do strugle a bit.我是编程初学者,有点挣扎。 So I'm building a TCP peer to peer Chat and that requires me to divide the tasks -> Threads.所以我正在构建一个 TCP 点对点聊天,这需要我划分任务-> 线程。 So I want to built a Thread for the "writing" part of that connection (Scanner, DataOutputStream etc.) In order to do that i implemented Runnable and that forces me to write my Thread in the overwritten run() method.因此,我想为该连接的“写入”部分(扫描仪、DataOutputStream 等)构建一个线程。为了做到这一点,我实现了 Runnable,这迫使我在覆盖的 run() 方法中写入我的线程。 Now I have a bit of a problem, because in Order to send my messages out to the "other end (another client) I need the "socket.getOutputStream" but I cant use it in the run() method and i dont know how to fix this problem, sitting already a week on this problem. Any ideas?现在我有一点问题,因为为了将我的消息发送到“另一端(另一个客户端)我需要“socket.getOutputStream”但我不能在 run() 方法中使用它而且我不知道如何解决这个问题,已经坐了一个星期了。有什么想法吗?

public class ClientHorcher implements Runnable {

    public static void main(String[] args) {
        
        try {
            ServerSocket serverSocket = new ServerSocket(11111);
            System.out.println("Waiting For Connection:-");
            Socket socket = serverSocket.accept();
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
            String nickname;
            System.out.print("Gib einen Nickname ein: ");
            nickname = scanner.nextLine();
            while (true) {
                String vonMsg = datenRein.readUTF(in);
                System.out.println("Client:-" + vonMsg);
                if (vonMsg.equals("exit")) {
                    System.out.println("Beenden!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    serverSocket.close();
                    System.exit(0);
                }

                System.out.print(nickname + ":-");
                String zuMsg = scanner.nextLine();
                datenRaus.writeUTF(zuMsg);
                if (zuMsg.equals("exit")) {
                    System.out.println("Quiting!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    serverSocket.close();
                    System.exit(0);
                }
            }
        } catch (IOException e) {
        
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
       
        
    }

}`
`public class ClientVerbinder implements Runnable  {
    


    public static void main(String[] args) {

        try {
            Socket socket = new Socket("Localhost", 11111);
            System.out.println("Connected");
            Scanner scanner = new Scanner(System.in);
            DataInputStream datenRein = new DataInputStream(socket.getInputStream());
            DataOutputStream datenRaus = new DataOutputStream(socket.getOutputStream());
            String nickname;
            System.out.print("Gib einen Nickname ein: ");
            nickname = scanner.nextLine();

            while (true) {
                System.out.print(nickname+":-");
                String zuMsg = scanner.nextLine();
                datenRaus.writeUTF(zuMsg);
                if (zuMsg.equals("exit")) {
                    System.out.println("Beenden!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    System.exit(0);
                }
                String vonMsg = datenRein.readUTF();
                System.out.println("CLient"+":-" + vonMsg);
                if (vonMsg.equals("exit")) {
                    System.out.println("Quiting!!!");
                    datenRein.close();
                    datenRaus.close();
                    scanner.close();
                    socket.close();
                    System.exit(0);
                }
            }
        } catch (UnknownHostException e) {
            
            e.printStackTrace();
        } catch (IOException e) {
            
            e.printStackTrace();
        }

    }
    @Override
    public void run() {
       
        
    
    }

}

Multiple possibilities.多种可能性。

  1. Use static variables.使用 static 变量。 Normally you would not do that, but because your code is all-static, you could通常你不会那样做,但是因为你的代码是全静态的,你可以

  2. Use member variables in an OO-style code.在 OO 风格的代码中使用成员变量。

  3. If you wanted to do it properly, you'd split the server into two parts:如果你想正确地做到这一点,你可以将服务器分成两部分:

    1. The ServerSocket listener that only listens to connections ( Socket connectionToClient = ss.accept ), and whenever a connection comes in, creates a new ServerSocket 监听器只监听连接( Socket connectionToClient = ss.accept ),每当有连接进来时,都会创建一个新的
    2. ClientHandler, passes in the Socket, and the ClientHandler then starts its own thread internally ClientHandler,传入Socket,然后ClientHandler在内部启动自己的线程

This way, the ClientHandler has all the data it needs (again as member variables) and can work on its own concerns (aka 'separation of concerns).这样,ClientHandler 拥有它需要的所有数据(同样作为成员变量)并且可以处理它自己的关注点(又名“关注点分离”)。

Update更新

This is what I created.这就是我创造的。 Really simple.真的很简单。

  1. Start Server启动服务器
  2. Start 1st client启动第一个客户
  3. Start 2nd client启动第二个客户端
  4. In any client, type message在任何客户端中,键入消息
  5. Other client receives it其他客户收到

Classes:课程:

SimpleServer简单服务器

package stackoverflow.simplemtserver;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingDeque;

public class SimpleServer { // make it closeable and close sockets if this is not standalone



    public static void main(final String[] args) throws IOException {
        final int port = 7623;
        new SimpleServer(port);
    }



    final LinkedBlockingDeque<SimpleServerClientHandler> clientHandlers = new LinkedBlockingDeque<>();

    private final ServerSocket mServerSocket;

    public SimpleServer(final int pPort) throws IOException {
        mServerSocket = new ServerSocket(pPort);

        final Thread m = new Thread(() -> runLoop(), getClass().getSimpleName() + " Main Loop");
        m.start();
    }



    private void runLoop() {
        while (true) {
            try {
                System.out.println("Server waiting for connection...");
                @SuppressWarnings("resource") final Socket cs = mServerSocket.accept(); // do NOT close the socket here, no try-resource, will interrupt threaded communication!
                final SimpleServerClientHandler ch = new SimpleServerClientHandler(this, cs);
                clientHandlers.add(ch);
                System.out.println("Connection accepted, handler started. Handlers active: " + clientHandlers.size());

            } catch (final IOException e) {
                // handle this how you need it
                e.printStackTrace();
            }
        }
    }



    public void signOffClientHandler(final SimpleServerClientHandler pClientHandler) {
        clientHandlers.remove(pClientHandler); // we could also accommplish this using stack trace to avoid access from outside, but this is the easier solution
    }



    public void spreadMessageToClients(final String pMessageFromClient, final SimpleServerClientHandler pSimpleServerClientHandler) {
        for (final SimpleServerClientHandler ch : clientHandlers) {
            if (ch != pSimpleServerClientHandler) ch.relayMessageToClient(pMessageFromClient); // we can work with identity == and != here
        }
    }



}

SimpleServerClientHandler SimpleServerClientHandler

package stackoverflow.simplemtserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class SimpleServerClientHandler {



    private final SimpleServer      mParentServer;
    private final Socket            mClientSocket;
    private final DataInputStream   mDIS;
    private final DataOutputStream  mDOS;

    public SimpleServerClientHandler(final SimpleServer pSimpleServer, final Socket pCS) throws IOException {
        mParentServer = pSimpleServer;
        mClientSocket = pCS;

        mDIS = new DataInputStream(mClientSocket.getInputStream());
        mDOS = new DataOutputStream(mClientSocket.getOutputStream());
        final Thread t = new Thread(() -> runComms(), getClass().getSimpleName() + " Comms Loop");
        t.setDaemon(true); // threads now stop once server stops. this is NOT a soft exit
        t.start();
    }



    private void runComms() {
        try {
            try {
                while (true) {
                    // do all your logic here, work with DIS and DOS

                    final String messageFromClient = mDIS.readUTF();
                    if (messageFromClient == null) break;

                    if (!messageFromClient.startsWith("*")) mParentServer.spreadMessageToClients(messageFromClient, this);
                }

            } catch (final Exception e) {
                // TODO: handle exception
            }

        } finally {
            try {
                mClientSocket.close(); // also closes DataIn/Out
            } catch (final IOException e) { /* ignore */ }
            mParentServer.signOffClientHandler(this);
        }
    }



    public void relayMessageToClient(final String pMessageFromClient) {
        try {
            mDOS.writeUTF("*" + pMessageFromClient);
        } catch (final IOException e) {
            // ignore unless needed otherwise
        }
    }



}

SimpleClient简单客户端

package stackoverflow.simplemtserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class SimpleClient {



    public static void main(final String[] args) throws UnknownHostException, IOException {
        final String hostname = "localhost";
        final int port = 7623;

        try (final Socket s = new Socket(hostname, port);
                final DataInputStream dis = new DataInputStream(s.getInputStream());
                final DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                final Scanner scanner = new Scanner(System.in);) {

            final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
            t.setDaemon(true);
            t.start();

            while (true) {
                System.out.println("Enter message:");
                System.out.flush();
                final String msg = scanner.nextLine();
                if (msg == null) break;

                System.out.println("Spreading message: " + msg);
                dos.writeUTF(msg);
            }
        }
    }

    private static void runListenerLoop(final DataInputStream pDis) {
        while (true) {
            try {
                System.out.println("Waiting for incoming messages...");
                final String msg = pDis.readUTF();
                System.out.println("Received: " + msg);

            } catch (final SocketException e) {
                //              if ("java.net.SocketException: Connection reset".equals(e.getMessage())) 
                break;
            } catch (final IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }



}

From here on, there's now more ways you can extend this client/server communication:从这里开始,现在有更多方法可以扩展此客户端/服务器通信:

  • use opcodes (read/write int constants or enums before data) to distinguish for special operations and/or messages (like this here puts an asterisk in front of the string to prevent re-re-laying the same message indefinitely over the network)使用操作码(在数据之前读/写 int 常量或枚举)来区分特殊操作和/或消息(像这里这样在字符串前面放置一个星号,以防止在网络上无限期地重新铺设相同的消息)
  • read multiple strings for user, message, additional options读取用户、消息、附加选项的多个字符串
  • implement this is a user friendly UI so you dont have to use console I/O实现这是一个用户友好的 UI,因此您不必使用控制台 I/O

Update 2更新 2

The pure peer-to-peer solution is this one.纯粹的点对点解决方案就是这个。

  • If the app is run without params, it goes into listening mode, waiting for a connection.如果应用程序在没有参数的情况下运行,它将进入侦听模式,等待连接。
  • If the app is run with one arguments, it interprets it as listening port and also goes into listening mode.如果应用程序使用一个 arguments 运行,它会将其解释为侦听端口并进入侦听模式。
  • If the app is un with [hostname] [port] arguments, it will try to connect there如果应用程序未使用 [hostname] [port] arguments,它将尝试在那里连接

Example:例子:

  • start first app without arguments (listening)在没有 arguments 的情况下启动第一个应用程序(监听)
  • start second app with arguments "localhost 7642" (connecting)使用 arguments "localhost 7642" 启动第二个应用程序(连接)
  • both apps will now这两个应用程序现在都将
    • connect,连接,
    • then set up I/O resources,然后设置 I/O 资源,
    • then start the listening thread for incoming messages然后启动传入消息的侦听线程
    • then go into the read-keyboard-and-write-to-socket loop然后 go 进入读-键盘-写-套接字循环
  • now you can type a message in one of the apps, the other one will receive it现在您可以在其中一个应用程序中输入消息,另一个应用程序会收到它

p2p code:点对点代码:

package stackoverflow.simplemtserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class SimplePeerToPeerClient {



    static public final int DEFAULT_PORT = 7642;



    public static void main(final String[] args) throws UnknownHostException, IOException {
        if (args.length == 0) {
            System.out.println("Waiting on default port " + DEFAULT_PORT);
            waitForConnection(DEFAULT_PORT);
        } else if (args.length == 1) {
            final int port = Integer.parseInt(args[0]);
            System.out.println("Waiting on port " + port);
            waitForConnection(port);
        } else if (args.length == 2) {
            final String hostName = args[0];
            final int port = Integer.parseInt(args[1]);
            System.out.println("Connecting to " + hostName + " on port " + port);
            connectToOtherSide(hostName, port);
        } else throw new IllegalArgumentException("Invalid amount of argument! Need none (listen) or 2: [hostname] [port] (connect)");
    }



    private static void waitForConnection(final int pPort) throws IOException {
        try (final ServerSocket ss = new ServerSocket(pPort);) {
            @SuppressWarnings("resource") final Socket socket = ss.accept(); // will get closed later
            startComms(socket);
        } // closes ServerSocket after 1st connection
    }
    private static void connectToOtherSide(final String pHostName, final int pPort) throws UnknownHostException, IOException {
        @SuppressWarnings("resource") final Socket socket = new Socket(pHostName, pPort); // will get closed later
        startComms(socket);
    }



    private static void startComms(final Socket pSocket) throws IOException {
        try (
                final DataInputStream dis = new DataInputStream(pSocket.getInputStream());
                final DataOutputStream dos = new DataOutputStream(pSocket.getOutputStream());
                final Scanner scanner = new Scanner(System.in);) {

            // run the listener loop
            final Thread t = new Thread(() -> runListenerLoop(dis), SimpleClient.class.getSimpleName() + " Reader Thread");
            t.setDaemon(true);
            t.start();

            // run my keyboard-input-send loop
            while (true) {
                System.out.println("Enter message:");
                System.out.flush();
                final String msg = scanner.nextLine();
                if (msg == null) break; // empty input ends client

                System.out.println("Spreading message: " + msg);
                dos.writeUTF(msg);
            }

        } finally {
            try {
                pSocket.close();
            } catch (final IOException e) { /* ignore */ }
        }
    }



    private static void runListenerLoop(final DataInputStream pDis) {
        while (true) {
            try {
                System.out.println("Waiting for incoming messages...");
                final String msg = pDis.readUTF();
                System.out.println("Received: " + msg);

            } catch (final SocketException e) {
                //              if ("java.net.SocketException: Connection reset".equals(e.getMessage()))
                break;
            } catch (final IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }



}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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