Java是等待的最佳方式&;从客户那里获取数据
我开始使用JDK中的主网络包学习网络,通过几个示例,它非常简单。但现在我有兴趣制作多客户端应用程序,比如聊天系统 到目前为止,我的结构想法如下:Java是等待的最佳方式&;从客户那里获取数据,java,multithreading,sockets,networking,Java,Multithreading,Sockets,Networking,我开始使用JDK中的主网络包学习网络,通过几个示例,它非常简单。但现在我有兴趣制作多客户端应用程序,比如聊天系统 到目前为止,我的结构想法如下: public class Chat implements Packet { @Override public void processPacket(Session c) { String message = readMessage(c); System.out.println("Message: " +
public class Chat implements Packet {
@Override
public void processPacket(Session c) {
String message = readMessage(c);
System.out.println("Message: " + message);
}
private String readMessage(Session c) {
byte[] data = c.readBytes();
String message = null;
try {
message = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return message;
}
}
连接处理程序类,它处理传入的连接,并保存客户端列表。
如果找到新连接,创建一个新的客户端对象,启动它的线程(客户端对象将实现runnable,因此它将启动自己的循环服务,它将循环接收到的新数据包),并将其添加到列表中
我为每个客户机创建一个新线程,而不是在所有客户机之间循环,因为从客户机读取进程会停止整个执行,并等待客户机发送数据,这有点让我恼火,这是我的问题
我已经创建了一个简单的控制台应用程序,可以从客户端接收消息,但现在我想检测断开的连接。我读到bufferedReader.read()方法在用户未连接时返回-1,所以我想我可以每隔几秒钟循环一次,然后发送给每个客户端,但问题是,客户端必须发送一个数据包才能.read()读取它,所以假设您这样做。read()它将等待并停止整个线程,直到收到数据包为止(我想)
这是我当前从客户端获取消息的代码:
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
这就是我读取字节的方式:
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
好的,我的问题是:
添加is disconnected检测后,当我发送消息时,什么也没有发生。这可能是由于.read()停止并等待响应。但如果我再写一条消息,我会在服务器上得到消息
这是我临时的丑陋客户:
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 43594);
Scanner r = new Scanner(System.in);
PrintWriter out = new PrintWriter(socket.getOutputStream());
String input;
while(true) {
input = r.next();
if (input != null) {
sendMessage(input, out);
}
}
}
public static void sendMessage(String message, PrintWriter out) {
byte[] encoded = encode(message);
out.write(0);
out.println(encoded + "\n");
out.flush();
}
public static byte[] encode(String s) {
return DatatypeConverter.parseBase64Binary(s);
}
public static String decode(byte[] s) {
return DatatypeConverter.printBase64Binary(s);
}
}
我的问题是:在不让应用程序等待并每次实际循环的情况下,从客户机读取数据的更好方法是什么?或者我应该有一个新的线程来检查用户是否在线,这样每个客户端就有2个线程
如果有人需要我的会话对象(客户端对象):
公共类会话扩展线程实现可运行{
专用套接字会话;
私人客户;
私人打印输出;
中的私有缓冲区读取器;
私有包处理程序包;
私有数据输入流数据输入;
私有连接处理器连接;
私人最终整数检查时间=1600;
私有最终整数最大时间=22000;
私人长期支票;
公开会话(套接字会话){
this.session=会话;
this.client=新客户机(this);
试一试{
这是setStream();
}捕获(IOE异常){
e、 printStackTrace();
}
this.packets=新的PacketHandler(this);
System.out.println(“[创建的新会话]:”+session.getRemoteSocketAddress());
}
public void setConnectionHandler(ConnectionHandler c){
这个连接=c;
}
公开募捐{
试一试{
这个.startClientService();
}捕获(IOE异常){
e、 printStackTrace();
}
}
public void setStream()引发IOException{
this.out=新的PrintWriter(this.session.getOutputStream());
this.in=new BufferedReader(new InputStreamReader(this.session.getInputStream());
this.dataIn=新的DataInputStream(this.session.getInputStream());
}
公共客户端getClient(){
将此文件退还给客户;
}
公共字节[]读取字节(){
内伦;
字节[]数据=null;
试一试{
len=this.dataIn.readInt();
数据=新字节[len];
如果(len>0){
此.dataIn.readFully(数据);
}
}捕获(IOE异常){
e、 printStackTrace();
}
返回数据;
}
公共字符串readMessage(){
试一试{
返回此.in.readLine();
}捕获(IOE异常){
e、 printStackTrace();
}
返回null;
}
公共布尔值未连接(){
试一试{
this.in.read();
this.lastCheck=System.currentTimeMillis();
返回true;
}捕获(IOE异常){
如果(!inConnection()){
System.out.println(“用户断开连接”);
试一试{
这是destruct();
}捕获(IOE1异常){
e1.printStackTrace();
}
}
}
返回false;
}
私有布尔连接(){
返回系统.currentTimeMillis()-lastCheck600){
System.out.println(System.currentTimeMillis()-this.checkTime);
if(this.isConnected()){
int packetType=this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct()引发IOException{
this.session.close();
this.connection.removeClient(this);
System.out.println(“会话终止”);
}
}
谢谢 虽然我没有时间查看所有的代码,但这里有两件事可以帮助您 1) 使用已定义的消息头。定义客户端将发送到服务器的每条消息的X字节数。使用这些字节定义消息的长度以及消息的类型。服务器知道此头的长度和布局,并使用它以特定的方式处理消息。示例可以是一个字节的头。值1可能是“我已连接”消息。2可能是我即将断开连接。3可能是我现在不在,4可能是收到的聊天信息 2) 有两种方法可以处理输入。首先是使用阻塞IO,并创建一个单独的线程来接收m
public class Session extends Thread implements Runnable {
private Socket session;
private Client client;
private PrintWriter out;
private BufferedReader in;
private PacketHandler packets;
private DataInputStream dataIn;
private ConnectionHandler connection;
private final int checkTime = 1600;
private final int maxTime = 22000;
private long lastCheck;
public Session(Socket session) {
this.session = session;
this.client = new Client(this);
try {
this.setStream();
} catch (IOException e) {
e.printStackTrace();
}
this.packets = new PacketHandler(this);
System.out.println("[New session created]: " + session.getRemoteSocketAddress());
}
public void setConnectionHandler(ConnectionHandler c) {
this.connection = c;
}
public void run() {
try {
this.startClientService();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setStream() throws IOException {
this.out = new PrintWriter(this.session.getOutputStream());
this.in = new BufferedReader(new InputStreamReader(this.session.getInputStream()));
this.dataIn = new DataInputStream(this.session.getInputStream());
}
public Client getClient() {
return this.client;
}
public byte[] readBytes() {
int len;
byte[] data = null;
try {
len = this.dataIn.readInt();
data = new byte[len];
if (len > 0) {
this.dataIn.readFully(data);
}
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
public String readMessage() {
try {
return this.in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public boolean isConnected() {
try {
this.in.read();
this.lastCheck = System.currentTimeMillis();
return true;
} catch (IOException e) {
if (!inConnection()) {
System.out.println("User disconnected");
try {
this.destruct();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return false;
}
private boolean inConnection() {
return System.currentTimeMillis() - lastCheck < this.maxTime;
}
public void startClientService() throws IOException {
while(!this.session.isClosed()) {
if (System.currentTimeMillis() - this.checkTime > 600) {
System.out.println(System.currentTimeMillis() - this.checkTime);
if (this.isConnected()) {
int packetType = this.dataIn.readInt();
packets.getPacket(packetType);
}
}
}
}
public void destruct() throws IOException {
this.session.close();
this.connection.removeClient(this);
System.out.println("Session killed");
}
}