Java Socket:我的服务器输入流无法从客户端输出流读取?

4

编辑:我知道这是很长的,但有人知道如何编写套接字程序吗?

我的问题让我有点困惑。我在一台计算机上运行服务器,在另一台计算机上连接了客户端。当我从客户端输入消息并发送它时,服务器似乎没有收到它。有人知道为什么吗?因为我已经花了3个小时测试打印到控制台,但无法解决这个问题。我对套接字比较新,如果我只是一个白痴,请不要太苛刻。

这是我客户端的代码:

import java.net.*;
import java.util.Scanner;
import java.io.*;

public class SocketClient {

public static void main(String [] args) {
    String host = "************";
    int port = 25565;

    StringBuffer instr = new StringBuffer();
    String TimeStamp;
    System.out.println("SocketClient initialized");

    try {
        InetAddress address = InetAddress.getByName(host);
        Socket connection = new Socket(address, port);

        BufferedOutputStream bos = new     BufferedOutputStream(connection.getOutputStream());
        OutputStreamWriter osw = new OutputStreamWriter(bos, "US-ASCII");

        Scanner scan = new Scanner(System.in);
        String message = scan.nextLine();

        TimeStamp = new java.util.Date().toString();
        String process = "Server called on " + host + ":" + port + " at " + TimeStamp + ": " + message + (char) 13;

        osw.write(process);
        osw.flush();

        BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());

        InputStreamReader isr = new InputStreamReader(bis, "US-ASCII");

        int c;
        while ( (c = isr.read()) != 13)
            instr.append( (char) c);

        connection.close();
        System.out.println(instr);

    } catch (UnknownHostException e) {
        System.err.println("UnknownHostException: " + e);
    } catch (IOException e) {
        System.err.println("IOExcepion: " + e);
    }
}
}

这里是连接客户端和服务器的代码:

import java.io.IOException;
import java.net.*;

public class MultipleSocketServer {

public static Socket connection;
public static String name = "Tyler's Server";
public static int limit = 2;
public static Thread[] clients = new Thread[limit];
public static int current = 0;
public static int port = 25565;
public static String[] connected = {"", ""};
public static ServerSocket socket;

public static void main(String[] args) {
    System.out.println("Server starting...");
    try {
        ServerSocket socket = new ServerSocket(port);
        while(true) {
            Socket connection = socket.accept();
            String ip = connection.getRemoteSocketAddress().toString().substring(1, 13);
            loop:
            for(int i = 0; i < connected.length; i++) {
                if(connected[0].equals(ip) || connected[1].equals(ip)) {
                    break loop;
                }else if(!connected[i].equals(ip)) {
                    connected[i] = ip;
                    System.out.println(ip);
                    MultiServer_Client client = new     MultiServer_Client(connection, i);
                    Thread run = new Thread(client);
                    run.start();
                    break loop;
                }
            }
        }
    } catch (IOException e1) {
        System.out.println("Could not bind server on: " + port);
        System.exit(-1);
    }
}
}

以下是处理每个已连接客户端的代码:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class MultiServer_Client implements Runnable {

public String time;
public Socket client;
public StringBuffer process = new StringBuffer();

public BufferedInputStream inputStream;
public InputStreamReader reader;

public BufferedOutputStream outputStream;
public OutputStreamWriter writer;

public boolean connected = true;

public int ID;

public MultiServer_Client(Socket connection, int i) {
    client = connection;
    ID = i;
    try {
        inputStream = new BufferedInputStream(client.getInputStream());
        reader = new InputStreamReader(inputStream);

        outputStream = new BufferedOutputStream(client.getOutputStream());
        writer = new OutputStreamWriter(outputStream, "US-ASCII");
    } catch (IOException e) {
        System.out.println("IOException: " + e);
    }
    System.out.println("Client connected...");
    write("Connected to " + MultipleSocketServer.name);
}

public void run() {
    while(connected) {
        write("hi");
    }
    System.out.println("Disconnecting client...");
}

public void write(String authen) {
    try {
        time = new java.util.Date().toString();
        String message = time + ": " + authen + (char) 13;
        writer.write(message);
        writer.flush();
    } catch (IOException e) {
        connected = false;
        MultipleSocketServer.connected[ID] = "";
    }
}

public void read() {
    //read from client
    int character;
    process = new StringBuffer();
    try {
        while ((character = reader.read()) != 13) {
            process.append((char) character);
        }
        System.out.println(process);
        process.delete(0, process.length());
    } catch (IOException e) {
        connected = false;
        MultipleSocketServer.connected[ID] = "";
    }
}
}

很抱歉我不能提供太多帮助。正如我所说,我对套接字还很陌生,而且似乎没有其他人有这样的问题...谢谢 :)


1
每当异常发生时,您似乎会默默地断开连接而不记录异常本身。可能是由于您的代码中出现了异常,导致服务器断开了客户端的连接吗? - Dawood
在我的服务器的write()和read()方法中,如果代码触发了异常,服务器会像关闭客户端一样退出。当出现任何异常时,我也会在客户端类中打印出所有内容。我真的很困惑哈哈哈。不过还是谢谢你的建议。 - MrDrProfessorTyler
另外,每当我循环执行socket.accept()以将客户端连接到服务器时,read()和write()都能正常工作,并且连接完美无缺,但它不允许我跟踪不同的客户端,一个计算机可以在服务器上运行无限数量的客户端。没有解决方法吗? - MrDrProfessorTyler
你的写入方法抛出了一个“Broken Pipe”SocketException异常。你的服务器没有关闭,因为它用IOException捕获了它。添加e.printStackTrace();以查看它。 - Joshua
当我调用write()时它不会捕捉任何东西?它完全运行,但客户端不会响应,read()在while()循环中被卡住。 - MrDrProfessorTyler
你能描述一下预期的行为应该是什么吗? - Dawood
1个回答

6
您的代码问题不在于“sockets”,而是您的通信协议。您实际上在服务器有机会写出“hi”之前关闭了套接字。
为了调试此问题,您需要减少程序的复杂性。您的程序中有许多没有意义或不重要的东西。
关于套接字,有一些背景知识。有两种类型的套接字:“ServerSocket”和“Socket”。ServerSocket有点像秘书。它的唯一工作就是监听呼叫并将其传递。这就是“accept”的作用。在任何客户端连接之前,accept()将阻塞,直到它收到一个连接。一旦客户端连接,accept返回表示连接的Socket。
常规的Socket是所有工作发生的地方。您可以将其视为电话连接。您可以使用OutputStream与远程人员进行交流,并使用InputStream进行侦听。挑战在于您需要为两个套接字创建某种通信(称为协议)以进行通信。
你需要确定如何分隔命令。如果你想要一个“长度”分隔的协议,你可以传递一个固定长度的数字,然后是数据,或者你可以使用特殊字符作为消息的结尾(你目前正在使用这种方式)。对于快速而简单的方法,我经常使用后者,并加上换行符。最简单的方法是使用PrintWriter进行写入,使用Scanner进行读取。
下一步是确定客户端和服务器的通信模式。将其视为来回传递球。如果客户端说了什么,另一方应该在听(反之亦然)。
一旦协议和逻辑被确定,你就可以将处理服务器端的逻辑移动到单独的线程中(称为工作模式),以便服务器可以同时处理多个客户端。如果你想进一步发展,你可以实现一个带有线程池的反应器,以便服务器不会耗尽线程,但那可能是另一天/问题。
我建议遵循Java套接字教程:http://docs.oracle.com/javase/tutorial/networking/sockets/index.html

谢谢,我成功地修正了代码并优化了效率。不过我发现客户端存在一个大问题。当我写入和读取字符串时,一直在重新连接服务器。非常感谢。 - MrDrProfessorTyler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接