多线程客户端 - 服务器聊天,使用套接字 [英] multithread client-server chat, using sockets

查看:123
本文介绍了多线程客户端 - 服务器聊天,使用套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是我的客户:

  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;
when(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(处理协议时出错+ e);
}
}
}

}

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

}

p>

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

LOG.trace );
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 +已添加!);
exec.execute(new ServerThread(socket,in,out));

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

ServerThread。

  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);

私有XML协议;
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private String buffer =; //可能存在另一个。方式,但它不工作
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(也许先登录?

}
* /
LOG.trace(从用户获取消息:+ 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(Read from stream:+ e);
} catch(JAXBException e){
LOG.error(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;
}
}


解决方案将需要多线程的客户端和服务器。客户端将需要一个线程来侦听来自服务器的消息,并将它们写入他/她的屏幕,并且一个线程等待他/她的键盘输入并将其发送到服务器。同样,对于与服务器的每个连接,它将需要一个线程等待来自客户端的输入,并且一个线程将其他用户的输出发送到客户端。



'看到传入消息,直到你按enter是因为客户端while循环。它现在已注释掉,但它看起来像你的循环习惯:

- 从服务器读取传入的消息\\ b $ b - 从键盘读取输入_
- 发送输入到服务器



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



从我的理解,创建JAXBContext的另一个词是一个昂贵的操作。您不需要在每次发送消息时重新创建它。请考虑在您的服务器和客户端中初始化一个,然后为每个marshall / unmarshall重新使用它。


Server and client communicating with my own protocol which looks like XMPP. I should to realize chat application. So when one user write String it immedeatly should be sended to other client through the server. I have method sendToAll on server. But user see the message of other user only when it press enter. How can user receive messages without pressing enter button?

So this is my client:

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();
}

}

And Server with 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();
    }
}

ServerThread.

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;
    }
}

解决方案

You will need to multi-thread both the client and server. The client will need one thread that listens for messages from the server and writes them to his/her screen and one thread that waits for his/her keyboard input and sends it to the server. Likewise for each connection to the server, it will need a thread waiting for input from the client and one thread sending output from other users to the client.

The reason you don't see incoming messages until you press enter is because of the client while loop. It's commented out now, but it looks like your loop used to:
- Read incoming messages from server
- Read input from keyboard
- Send input to server

So you read whatever was available from the server, and then the client waits for more keyboard input before reading from the server again (in the next iteration).

Another word of advice, from my understanding, creating JAXBContext can be an expensive operation. You don't need to recreate it every time you send a message. Consider initializing one in your server and client and then reusing it for each marshall/unmarshall.

这篇关于多线程客户端 - 服务器聊天,使用套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆