Я изучаю сокеты в java, но когда я запускал программу, которая отправляет сообщения с клиентской стороны на серверную, она не показывает сообщение. Если я ввожу текст на стороне клиента, он не отображается на стороне сервера, но если я набираю endProcess, он перестает работать. Это означает, что сообщение проходит, оно просто не отображается.
Мой код Client.java находится здесь:
import java.net.*;
import java.io.*;
public class Client{
Socket soc;
DataInputStream dis;
DataOutputStream dos;
public Client(){
try{
soc = new Socket("(Address)",5000);
System.out.println("Connection Established");
dis = new DataInputStream(System.in);
dos = new DataOutputStream(soc.getOutputStream());
System.out.println("Streams connected");
}catch(UnknownHostException u){
System.out.println(u);
}catch(IOException i){
System.out.println(i);
}
String line = "";
while(!line.equals("endConnection")){
try{
line = dis.readUTF();
dos.writeUTF(line);
}catch(IOException i){
System.out.println(i);
}
}
try {
soc.close();
dis.close();
dos.close();
} catch (Exception e) {
System.out.println(e)
}
}
public static void main(String[] args) {
new Client();
}
}
Вот мой код Server.java:
import java.net.*;
import java.io.*;
public class Server {
ServerSocket serSoc;
Socket soc;
DataInputStream dis;
public Server(){
try {
serSoc = new ServerSocket(5000);
System.out.println("Server Online");
soc = serSoc.accept();
System.out.println("Client Connected");
dis = new DataInputStream(new BufferedInputStream(soc.getInputStream()));
String line = "";
System.out.println("Waiting for input...");
while(!line.equals("endConnection")){
line = dis.readUTF();
System.out.println(line);
}
System.out.println("Client disconnected");
soc.close();
dis.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new Server();
}
}




Здесь много проблем.
line = dis.readUTF(); dos.writeUTF(line);
Это не сработает; Строка dis.readUTF() переходит в состояние блокировать (замораживание), пока строка не будет прочитана. Проблема в том, что иногда вам нечего отправить, и в этом случае вы хотите прочитать, и что-то, что вам нечего читать, и в этом случае вы хотите отправить. На практике вам нужно полностью перепроектировать это; нужно 2 нити. В этот момент вы сталкиваетесь с проблемами многоядерности, нуждающимися в примитивах синхронизации и/или классах java.util.concurrent для всех данных, которые совместно используются двумя потоками.
В качестве альтернативы примите модель, которая строго требует или вытягивает (где в любой момент времени обе стороны уже знают, кто может отправить, и если другая сторона хочет отправить, они просто не могут. Например, каждая сторона отправляет просто «НЕЧЕГО ДЕЛАТЬ» сообщение каждую секунду, каждый раз меняя местами.Это, конечно, довольно неэффективный алгоритм.Но его можно было бы написать без участия нескольких потоков.
dos.writeUTF(line);
На самом деле это ничего не отправляет или, по крайней мере, не гарантирует. Чтобы отправить какие-либо данные в Интернете, они упаковываются в пакет, который имеет много накладных расходов. Таким образом, все буферизуется до тех пор, пока не будет отправлен полный пакет. Это означает, что эта линия ничего не делает. Он просто заполняет буфер, пакеты не отправляются. Сначала нужно закрыть или промыть. dos.flush() может поможет. Это большая проблема, потому что позже вы делаете:
soc.close(); dis.close(); dos.close();
Вы сначала закрываете сокет, который, ну, закрывает сокет. Затем вы закрываете потоки, которые также будут отправлять все, что все еще застряло в буфере, за исключением того, что это не удастся, потому что сокет уже закрыт. Другими словами, строчка, которую вы .writeUTF()-редали? Он никогда не доберется туда. Сначала вы засовываете его в буфер, затем закрываете сокет, затем отправляете буфер, который не будет работать, так как сокет уже закрыт.
} catch (Exception e) { System.out.println(e); }
Ужасный. Не делай этого. Ваш код реагирует на любую проблему, печатая что-то и просто продолжаю идти. Это означает, что если что-то пойдет не так, клиент начнет спамить бесконечную кавалькаду трассировок исключений и, если повезет, заблокирует систему. Вы хотите, чтобы код прекращал работу при возникновении проблем. Самый простой способ, безусловно, — просто прикрепить throws IOException к вашему конструктору и основному методу, что разрешено. Отдалённый второй лучший вариант — настроить блоки захвата «да что угодно» как throw new RuntimeException("unhandled", e); вместо e.printStackTrace().
То, что вы делаете (System.out.println(e);), это еще хуже — вы отбрасываете чрезвычайно полезную информацию, такую как трассировка стека и причинно-следственная цепочка.