【问题标题】:Java Soket Threaded Server sending messages back to specific clientJava Socket Threaded Server 将消息发送回特定客户端
【发布时间】:2018-11-10 06:09:06
【问题描述】:

我正在开发一个客户端-服务器 Java GUI(Swing) 应用程序,我已经成功创建了从客户端接收消息的线程服务器类,以及一个向服务器发送消息的客户端类,客户端和服务器都是 GUI 应用程序,我我正在为我的网吧开发一个局域网订购系统.. 我是套接字编程的新手,我现在需要的是一种方法,当服务器 GUI 应用程序的用户通过单击消息到达时更改图标的 JLabel 来查看 GUI 中的订单时,将消息从服​​务器发送到客户端。

那么如何将消息从服​​务器发送到发送触发该特定 JLabel 消息的特定客户端?以及如何向包含该消息的客户端用户显示 JOptionpane(客户端有多个 JPanel 类)

发送消息的客户端类:

package questorderingsystem.engine;

import java.io.BufferedWriter; 
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
    public class SendItemAndIp {

    private static Socket socket;
    public static String message = "";
    public static void sendToServer(String item) throws UnknownHostException, IOException{
    InetAddress IP= InetAddress.getLocalHost();
    String ipadr = IP.toString();
    String PCNUM = ipadr.substring(ipadr.length() - 2);

    //IP SERVERAA 
    String host = "192.168.55.151";
    int port = 1978;
        InetAddress address = InetAddress.getByName(host);
        socket = new Socket(address, port);
        //Send the message to the server
        OutputStream os = socket.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter bw = new BufferedWriter(osw);
        String oneLine = item.replace("\n", "%");
        String sendMessage = oneLine +"/"+ PCNUM;
        bw.write(sendMessage);
        bw.flush();
        socket.close();
}
}

线程服务器

package questorderingsystemserver;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ThreadedEchoServer {

static final int PORT = 1978;

public static void startServer() {
    ServerSocket serverSocket = null;
    Socket socket = null;

    try {
        serverSocket = new ServerSocket(PORT);
    } catch (IOException e) {
        e.printStackTrace();

    }
    while (true) {
        try {
            socket = serverSocket.accept();
        } catch (IOException e) {
            System.out.println("I/O error: " + e);
        }
        // new thread for a client
        new EchoThread(socket).start();
    }
}
}

回声服务器

package questorderingsystemserver;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JLabel;

public class EchoThread extends Thread {
protected Socket socket;



}
public EchoThread(Socket clientSocket) {
    this.socket = clientSocket;
}
public void run() {
    InputStream inp = null;
    BufferedReader brinp = null;
    DataOutputStream out = null;
    try {
        inp = socket.getInputStream();
        brinp = new BufferedReader(new InputStreamReader(inp));
        out = new DataOutputStream(socket.getOutputStream());
    } catch (IOException e) {
        return;
    }
    String line;
    while (true) {
        try {
            line = brinp.readLine();
            if ((line == null) || line.equalsIgnoreCase("QUIT")) {
                socket.close();
                return;
            } else {
                //do something

                out.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } catch (UnsupportedAudioFileException ex) {
            Logger.getLogger(EchoThread.class.getName()).log(Level.SEVERE, null, ex);
        } catch (LineUnavailableException ex) {
            Logger.getLogger(EchoThread.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
}

【问题讨论】:

  • 如果需要我可以把整个项目发给我,只是我不知道上传到哪里?
  • 客户端发送数据后,您似乎关闭了客户端连接。如果客户端关闭了与服务器的连接,该客户端应该如何从服务器接收数据?
  • 根据@VinceEmigh,您应该为每个客户端创建一个套接字,并在客户端应用程序的整个生命周期中使用它。
  • 好的,所以我删除客户端类中的 socket.close ?然后在客户端读取输入,就像我从客户端读取服务器一样?但是如何从服务器定位特定客户端? @VinceEmigh
  • 任务是否应该同步?这意味着您在继续执行程序或异步之前等待服务器的响应?你能提供你的客户的“阅读逻辑”吗?

标签: java multithreading sockets server


【解决方案1】:

套接字建立端到端连接,因此它连接到另一个特定的每个套接字。 ServerSocket 略有不同。看看ServerSocket::accept的返回。返回的对象是Socket。不仅是一个套接字,而是一个直接连接到发出请求的客户端的套接字。由于您为每个ServerSocket#accept 创建了一个新的EchoThread,因此每个EchoThread 都与它自己的客户端连接。

您已经在从套接字读取数据以检查连接是否已关闭或是否已发出“退出命令”。现在您可以简单地在您的 else-clause 中使用之前创建的 DataOutputStream 进行响应:

while (true) {
    try {
        line = brinp.readLine();
        if ((line == null) || line.equalsIgnoreCase("QUIT")) {
            socket.close();
            return;
        } else {
            //writing here:
            out.write("Some response text\n".getBytes());
            out.flush();
        }
    } catch (IOException e) {
      ...
    } ...
}

但请注意,您的回复字符串需要以 '\n' 字符结尾,具体取决于您客户的“阅读逻辑”。

【讨论】:

  • 怎么做 out.write("adasd\n".getBytes());来自服务器的 gui,以及如何在客户端读取该消息? @L.Spillner
  • @AleksandarStojanovic 这在很大程度上取决于您的项目结构和您想要的行为。在 GUI 方面,我经常使用MVP pattern,但您目前可能有另一个实现。而如何“阅读”响应取决于许多因素。如果是同步或异步,你想读的时间等等,我帮不了你。但可以肯定的是,每个连接都必须始终使用相同的套接字。
【解决方案2】:

您几乎完成了,因为您将第一个命令指定为“QUIT”,因此您可以根据需要执行更多命令。

好的部分是使用BufferedReader 和DataOutputStream 处理输入和输出。

如果您喜欢使用字符串在客户端和服务器之间进行通信,请注意,因此您可以使用PrintStream 或PrintWriter 而不是DataOutputStream。

在线程服务器文件/类中,将这一行 new EchoThread(socket).start(); 放在 try 中接受套接字之后(现在是安全的)。

在客户端类/文件中,当您向服务器发送一些命令时,您可能也会期待一些结果。因此,就像您创建的 echo 类一样,您可以为客户端执行相同的操作并处理响应。

【讨论】:

    猜你喜欢
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 2016-09-19
    • 2012-03-06
    • 1970-01-01
    相关资源
    最近更新 更多