当前位置: 首页 > 知识库问答 >
问题:

多线程客户端-服务器聊天,使用套接字

赫连越
2023-03-14

服务器和客户端使用我自己的协议进行通信,看起来像XMPP。我应该实现聊天应用。因此,当一个用户编写String时,它应该立即通过服务器发送给其他客户端。我在服务器上有sendToAll方法。但用户只有在按下回车键时才能看到其他用户的消息。用户如何在不按回车键的情况下接收消息?

这是我的客户:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.apache.log4j.Logger;

import dataart.practice.protocols.XMLProtocol;

public class Client {
public static final String SERVER_HOST = "localhost";
public static final Integer SERVER_PORT = 4444;
public static final Logger LOG = Logger.getLogger(Client.class);
private static BufferedReader in;
private static PrintWriter out;
private static BufferedReader inu;

public static void main(String[] args) throws IOException {

    System.out.println("Welcome to Client side");
    XMLProtocol protocol = new XMLProtocol();
    Socket fromserver = null;

    fromserver = new Socket(SERVER_HOST, SERVER_PORT);

    in = new BufferedReader(new InputStreamReader(fromserver.getInputStream()));

    out = new PrintWriter(fromserver.getOutputStream(), true);

    inu = new BufferedReader(new InputStreamReader(System.in));

    String fuser, fserver;
    while (true){
        if(in.ready()){//fserver = in.readLine()) != null) {
        System.out.println("asdasdsd");

        fuser = inu.readLine();
        if (fuser != null) {
            if (fuser.equalsIgnoreCase("close"))
                break;
            if (fuser.equalsIgnoreCase("exit"))
                break;

            protocol.setComId((long) 0);
            protocol.setContent(fuser);
            protocol.setLogin("Guest");

            try {

                JAXBContext jaxbContext = JAXBContext.newInstance(XMLProtocol.class);
                Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
                jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
                jaxbMarshaller.marshal(protocol, out);
                out.flush();

            } catch (JAXBException e) {
                LOG.error("Error while processing protocol" + e);
            }
        }
        }

    }

    out.close();
    in.close();
    inu.close();
    fromserver.close();
}

}

以及带有ServerThread的服务器。

public static void main(String[] args) throws IOException {

    LOG.trace("Server started");
    ServerSocket s = new ServerSocket(SERVER_PORT);

    try {
        while (true) {
            LOG.trace("Waiting for connections...");
            Socket socket = s.accept();
            try {
                // new ServerThread(socket);
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
                userCounter++;
                addUser("Guest" + userCounter, out);
                LOG.trace("User " + userCounter + " has been added!");
                exec.execute(new ServerThread(socket, in, out));

            } catch (IOException e) {
                socket.close();
            }
        }
    } finally {
        s.close();
    }
}

服务器线程。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.Socket;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

import org.apache.log4j.Logger;

import dataart.practice.protocols.XMLProtocol;
import dataart.practice.serverUtils.Commands;

public class ServerThread implements Runnable {
    private static final Logger LOG = Logger.getLogger(ServerThread.class);

    private XMLProtocol protocol;
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;
    private String buffer = "";// may be exist another. way but it's not working
    private Boolean login = false;

    public ServerThread(Socket s, BufferedReader in, PrintWriter out) throws IOException {
        this.in = in;
        this.out = out;
        out.println("</XMLProtocol>");
        socket = s;
        new Thread(this);       
    }

    public void run() {
        try {
            while (true) {              
                if ((buffer = in.readLine()) != null) {
                    if (buffer.endsWith("</XMLProtocol>")) {
                        protocol = getProtocol(buffer);
                        //Server.onlineUserList.put(protocol.getLogin(), out);
/*                      if (!login){
                            out.println("Maybe login first?");
                            
                        }
*/                      
                        LOG.trace("Getting message from user: " + protocol.getLogin() + " recived message: " + protocol.getContent());
                        ///out.println(protocol.getLogin() + " says:" + protocol.getContent());
                        Server.sendToAll(protocol.getContent()+"</XMLProtocol>");
                    
                        
                    } else {
                        LOG.trace("Nop protocol do not send with it end");
                    }
                }
            }
        } catch (IOException e) {
            LOG.error("Error in reading from stream: " + e);
        } catch (JAXBException e) {
            LOG.error("Error in Marshalling: " + e);
        } finally {
            try {
                socket.close();
                LOG.trace("Socket closed");
            } catch (IOException e) {
                LOG.error("Socket no closed" + e);
            }
        }
    }

    public XMLProtocol getProtocol(String buffer) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(XMLProtocol.class);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        return (XMLProtocol) jaxbUnmarshaller.unmarshal(new StreamSource(new StringReader(buffer)));
    }

    public Boolean loginIn(XMLProtocol protocol) {

        return true;
    }
}

共有2个答案

万承志
2023-03-14

试试这个,

请勿< code >将BufferedReader()与PrintWriter一起使用.....< code>PrintWriter本身就是字节级套接字数据和字符形式之间的桥梁。

例如:

我展示了对于单个客户端,对n个客户端使用while循环

ServerSocket s = new ServerSocket(4444);

Socket incoming = s.accept();

OutputStream output = s.getOutputStream();

PrintWriter pw = new PrintWriter(output,true);

System.out.println(pw.write(新扫描仪(System.in). nextLine()));

劳宇
2023-03-14

您将需要对客户端和服务器进行多线程处理。客户端需要一个线程来侦听来自服务器的消息并将其写入他/她的屏幕,以及一个线程等待他/她的键盘输入并将其发送到服务器。同样,对于与服务器的每个连接,它都需要一个线程等待来自客户端的输入,以及一个线程将输出从其他用户发送到客户端。

在按下回车键之前看不到传入消息的原因是因为客户端同时循环。它现在被注释掉了,但看起来像您的循环用于:
-从服务器读取传入消息
-从键盘读取输入
-将输入发送到服务器

因此,您可以从服务器读取任何可用的内容,然后客户端在再次从服务器读取之前等待更多的键盘输入(在下一次迭代中)。

另一个建议,根据我的理解,创建JAXBContext可能是一项昂贵的操作。您无需在每次发送邮件时都重新创建它。考虑在服务器和客户端中初始化一个,然后为每个编组/解组组重用它。

 类似资料:
  • 问题内容: 服务器和客户端使用我自己的协议(类似于XMPP)进行通信。我应该实现聊天应用程序。因此,当一个用户写String时,应该立即将其通过服务器发送给其他客户端。我在服务器上有sendToAll方法。但是用户只有在按Enter时才能看到其他用户的消息。 用户如何在不按Enter键的情况下接收消息? 这是我的客户: 和带有ServerThread的服务器。 ServerThread。 问题答案

  • 我已经实现了一个通过套接字进行通信的全局聊天。客户端写入一条消息,发送到服务器,然后服务器将消息发回给所有客户端。每个客户端都由一个名为ClientThread的类表示,因此每个客户端都是一个线程。每次新客户端连接时,我都会创建一个新的ClientThread实例,并将所有这些实例存储在列表中。现在我想实现一个私人聊天,这样每个客户端就可以私下与另一个客户端交谈(或者2,3或更多的群聊)。 我还想

  • 本文向大家介绍Java多线程实现聊天客户端和服务器,包括了Java多线程实现聊天客户端和服务器的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java聊天室代码,供大家参考,具体内容如下 主要涉及知识 ·Java中GUI程序的编写,包括事件监听机制。 ·Java的网络通信编程,ServerSocket,Socket类的使用。 ·Java中多线程的编程,Thread类,Runnable

  • 我需要在netty中有一个客户机/服务器通信,用于我的项目目的之一。所以我刚开始用一个handsOn来改进,我正在学习netty,我是一个初学者。 我尝试了一个简单的客户端服务器与Netty聊天。 客户端和服务器正在初始化,我可以看到服务器能够获得用于建立连接的客户端管道,但是当客户端发送消息时,它没有进入ServerAdapterHandler的messageReceived部分。下面是我的源代

  • 我想在java上创建一个客户机/服务器应用程序,服务器的IP地址为192.168.1.100,在端口4500上等待客户机请求。 客户端从键盘上读取字符串,向服务器发送连接请求。一旦建立了连接,它就会将字符串发送到服务器。 这是我尝试的代码: 对于服务者: 对于客户端: 但这段代码有一个问题: