Я работаю над крошечным java проектом, который может использовать TLS для связи с другими. Он состоит из двух частей: сервера и клиента. Вот класс с именем «MultiThreadServer» в серверной части:
public class MultiThreadServer implements Runnable {
SSLSocket ss;
public static Chatroom lobby;
public static HashMap<SSLSocket, Chatroom> ss_current_channels = new HashMap<SSLSocket, Chatroom>();
public static HashMap<SSLSocket, String> ss_nick = new HashMap<SSLSocket, String>();
public MultiThreadServer(SSLSocket ss) {
this.ss = ss;
}
/*
* args0 = jks file path => depreciated use file path "./server.cer" instead
* args0 = listen port
* args1 = password
*/
public static void main(String args[]) throws Exception {
lobby = new Chatroom("lobby");
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("./server.cer"), args[1].toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, args[1].toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, SecureRandom.getInstanceStrong());
SSLServerSocketFactory sssf = sc.getServerSocketFactory();
SSLServerSocket sss = (SSLServerSocket) sssf.createServerSocket(Integer.parseInt(args[0]));
System.out.println("\n\nServer created sucessfully!");
System.out.println("\nwaiting for connecting...\n\n");
while (true) {
SSLSocket ss = (SSLSocket) sss.accept();
System.out.println("A new client connected!");
//System.out.println(ss.hashCode());
(new Thread(new MultiThreadServer(ss))).start();
}
}
@Override
public void run() {
try {
if (ss_nick.get(ss) == null) {
ss_nick.put(ss, "anonymous");
}
if (ss_current_channels.get(ss) == null) {
ss_current_channels.put(ss, lobby);
lobby.UserJoin(ss);
}
BufferedReader br = new BufferedReader(new InputStreamReader(ss.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
String in;
while (true) {
while ((in = br.readLine()) != null) {
String[] command = ProtocolParser.parse(in);
if (command == null) {
continue;
}
switch (command[0]) {
case "SAY":
if (ss_current_channels.get(ss) == null) {
bw.write("you have to join a channel first\n");
bw.flush();
} else {
ss_current_channels.get(ss).appendLog(ss_nick.get(ss) + "> " + command[1]);
}
break;
case "JOIN": // direct continue to VIEW
try {
ss_current_channels.get(ss).UserLeave(ss);
ss_current_channels.put(ss, Chatroom.getChatroom(command[1])); // thrown at here
Chatroom.getChatroom(command[1]).UserJoin(ss);
} catch (NoSuchChannelException e) { //Create one
try {
new Chatroom(command[1]).UserJoin(ss);
ss_current_channels.put(ss, Chatroom.getChatroom(command[1]));
} catch (ChatroomExistsException e1) {
} // not possible
}
// change array to fulfill the condition "VIEW" wants
command = new String[]{ "VIEW", command[1], "100" };
case "VIEW":
String logs = Chatroom.getChatroom(command[1]).getLog(Integer.parseInt(command[2]));
bw.write(logs + '\n');
bw.flush();
break;
case "NICK":
ss_current_channels.get(ss).appendLog(
"Now " + ss_nick.get(ss) + " has changed his(her) nickname" + " to " + command[1]+"!");
ss_nick.put(ss, command[1]);
break;
default:
break;
}
}
}
} catch (SocketException se){
try {
ss_current_channels.get(ss).UserLeave(ss);
ss_nick.remove(ss);
ss_current_channels.remove(ss);
ss.close();
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (NoSuchChannelException e) {
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
bw.write("NoSuchChannel! Try JOIN channel!\n");
bw.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Когда я использую клиент для подключения к серверу, закрою клиент, затем снова подключусь и что-то напишу в сокет, следующие ошибки будут происходят на сервере:
javax.net.ssl.SSLProtocolException: Broken pipe (Write failed)
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:126)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259)
at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:988)
at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:233)
at java.base/sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:312)
at java.base/sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:316)
at java.base/sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:153)
at java.base/java.io.OutputStreamWriter.flush(OutputStreamWriter.java:254)
at java.base/java.io.BufferedWriter.flush(BufferedWriter.java:257)
at me.petjelinux.ServerChat.Server.Chatroom.messageUsers(Chatroom.java:59)
at me.petjelinux.ServerChat.Server.Chatroom.appendLog(Chatroom.java:65)
at me.petjelinux.ServerChat.Server.MultiThreadServer.run(MultiThreadServer.java:92)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.net.SocketException: Broken pipe (Write failed)
at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110)
at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
at java.base/sun.security.ssl.SSLSocketOutputRecord.deliver(SSLSocketOutputRecord.java:320)
at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:983)
... 10 more
Я знаю, что это исключение может быть вызвано записью в соединение, которое уже закрыто, но я просто не могу понять, как это произошло в этой ситуации (переподключиться с тем же клиентом), Может кто-нибудь объяснить и, возможно, предоставить способ исправить это? Спасибо! При необходимости я отправлю коды из клиентской части.