Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在简单的聊天程序中,服务器发送字符串数组列表,但客户端接收旧值_Java_Multithreading_Sockets_Client Server - Fatal编程技术网

Java 在简单的聊天程序中,服务器发送字符串数组列表,但客户端接收旧值

Java 在简单的聊天程序中,服务器发送字符串数组列表,但客户端接收旧值,java,multithreading,sockets,client-server,Java,Multithreading,Sockets,Client Server,我想用一台服务器和多个客户端创建一个简单的游戏。服务器将有几个哈希映射和数组列表。服务器将向客户端广播这些值,然后客户端可以逐个修改这些值并发送回服务器,然后服务器将向所有客户端广播更新的值 首先,我创建了服务器-客户端聊天应用程序。当客户端向服务器发送字符串消息时,服务器会将该字符串消息添加到其Arraylist中,并将该Arraylist广播给所有客户端。我使用了线程,这样多个客户端可以同时发送消息,但我还没有应用线程安全 让我们来讨论这个问题。当客户机第一次向服务器发送字符串时,服务器会很

我想用一台服务器和多个客户端创建一个简单的游戏。服务器将有几个哈希映射和数组列表。服务器将向客户端广播这些值,然后客户端可以逐个修改这些值并发送回服务器,然后服务器将向所有客户端广播更新的值

首先,我创建了服务器-客户端聊天应用程序。当客户端向服务器发送字符串消息时,服务器会将该字符串消息添加到其Arraylist中,并将该Arraylist广播给所有客户端。我使用了线程,这样多个客户端可以同时发送消息,但我还没有应用线程安全

让我们来讨论这个问题。当客户机第一次向服务器发送字符串时,服务器会很好地打印它,添加到它的arraylist中,然后将它广播到所有客户机,所有客户机也可以看到它。但下一次当客户端发送字符串消息时,服务器会接受它,添加到arraylist并广播它,但这次所有客户端都会得到旧的arraylist(只有一个首先添加的字符串的列表)。广播之前我已经打印了arraylist,它显示修改后的值,但在客户端,它只显示一个条目的列表

服务器代码的一部分

public class ServerGUI extends javax.swing.JFrame {

public static final int SERVER_PORT = 4000;
private ServerSocket ss;
ArrayList<String> al;
ArrayList<ClientHandler> clients;

public ServerGUI() {
    initComponents();
    setVisible(true);
    al = new ArrayList<>();
    clients = new ArrayList<>();
    initNet();
}

private void initNet() {
    Socket ds = null;
    try {
        ss = new ServerSocket(SERVER_PORT, 1);
        while (true) {

            ds = ss.accept();

            clients.add(new ClientHandler(ds));
        }
    } catch (Exception e) {

        System.out.println("shutting down server......");
    }
}

class ClientHandler extends Thread {

    private Socket ds;
    private ObjectOutputStream out;
    private ObjectInputStream in;

    public ClientHandler(Socket ds) throws Exception {
        this.ds = ds;
        out = new ObjectOutputStream(ds.getOutputStream());
        in = new ObjectInputStream(ds.getInputStream());
        start();
    }

    public ObjectOutputStream getOut() {
        return out;
    }

    public void run() {
        try {
            while (true) {
                acceptData(in);
                broadcastData();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("Finally called. socket closed");
            if (ds != null) {
                try {
                    ds.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

private void acceptData(ObjectInputStream in) throws Exception {
    System.out.println("acceptData called by " + Thread.currentThread().getName());
    String s = (String) in.readObject();
    al.add(s);
    jta.setText(al.toString());
}

private void broadcastData() throws Exception {
    System.out.println("broadcast called by " + Thread.currentThread().getName());
    System.out.println("al is : \n" + al);

    for (ClientHandler clnt : clients) {
        clnt.getOut().writeObject(al);
        clnt.getOut().flush();
    }
}
公共类ServerGUI扩展了javax.swing.JFrame{
公共静态最终int服务器_端口=4000;
专用服务器;
ArrayList al;
ArrayList客户;
公共服务器GUI(){
初始化组件();
setVisible(真);
al=新的ArrayList();
clients=newarraylist();
initNet();
}
私有void initNet(){
套接字ds=null;
试一试{
ss=新的服务器套接字(服务器端口,1);
while(true){
ds=ss.accept();
添加(新ClientHandler(ds));
}
}捕获(例外e){
System.out.println(“关闭服务器…”);
}
}
类ClientHandler扩展线程{
专用插座ds;
私有对象输出流输出;
私有对象输入流;
公共ClientHandler(套接字ds)引发异常{
这是1.ds=ds;
out=newObjectOutputStream(ds.getOutputStream());
in=newObjectInputStream(ds.getInputStream());
start();
}
public ObjectOutputStream getOut(){
返回;
}
公开募捐{
试一试{
while(true){
接受数据(in);
广播数据();
}
}捕获(例外e){
e、 printStackTrace();
}最后{
System.out.println(“最终调用.套接字关闭”);
如果(ds!=null){
试一试{
ds.close();
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
}
}
私有void acceptData(ObjectInputStream in)引发异常{
System.out.println(“由“+Thread.currentThread().getName()调用的acceptData”);
.readObject()中的字符串s=(字符串);
等。添加(s);
jta.setText(al.toString());
}
私有void broadcastData()引发异常{
System.out.println(“由“+Thread.currentThread().getName()调用的广播”);
System.out.println(“al为:\n”+al);
用于(ClientHandler clnt:客户){
clnt.getOut().writeObject(al);
clnt.getOut().flush();
}
}
客户端代码的一部分

public class ClientGUI extends javax.swing.JFrame {

public static final int SERVER_PORT = 4000;
public static final String SERVER_IP = "127.0.0.1";
private Socket s1;
private ObjectOutputStream out;
private ObjectInputStream in;
private ArrayList<String> al;

public ClientGUI() {
    initComponents();
    setVisible(true);
    initNet();
}

private void initNet() {
    try {
        s1 = new Socket(SERVER_IP, SERVER_PORT);
        out = new ObjectOutputStream(s1.getOutputStream());            
        in = new ObjectInputStream(s1.getInputStream());
        System.out.println("connected to server");

        new ReadData();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

class ReadData extends Thread {

    public ReadData() {
        start();
    }

    public void run() {
        System.out.println("client thread started");
        try {
            while (true) {
                al = (ArrayList<String>) in.readObject();
                System.out.println("client read completed, al is "+al);

                jta.setText(al.toString());                    
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt) {                                    
    try {
        out.writeObject(jtf.getText());
        out.flush();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
公共类ClientGUI扩展了javax.swing.JFrame{
公共静态最终int服务器_端口=4000;
公共静态最终字符串服务器\u IP=“127.0.0.1”;
专用插座s1;
私有对象输出流输出;
私有对象输入流;
私人ArrayList al;
公共客户端GUI(){
初始化组件();
setVisible(真);
initNet();
}
私有void initNet(){
试一试{
s1=新套接字(服务器IP、服务器端口);
out=newObjectOutputStream(s1.getOutputStream());
in=newObjectInputStream(s1.getInputStream());
System.out.println(“连接到服务器”);
新的ReadData();
}捕获(例外e){
e、 printStackTrace();
}
}
类ReadData扩展线程{
公共读取数据(){
start();
}
公开募捐{
System.out.println(“客户端线程已启动”);
试一试{
while(true){
.readObject()中的al=(ArrayList);
System.out.println(“客户端读取完成,al为”+al);
jta.setText(al.toString());
}
}捕获(例外e){
e、 printStackTrace();
}
}
}
private void textFieldActionPerformed(java.awt.event.ActionEvent evt){
试一试{
out.writeObject(jtf.getText());
out.flush();
}捕获(例外e){
e、 printStackTrace();
}
}

这是正常行为。如果发送相同的对象(您的ArrayList)多次发送到给定的
ObjectOutputStream
,流将在第一次发送完整的对象,并且在下一次只发送对此对象的引用。这就是允许发送对象图而不消耗太多带宽,也不进入无限循环的原因,因为
a
引用
b
which还引用了
a

要确保再次发送ArrayList,需要调用
ObjectOutputStream