Java服务器/客户端套接字停止响应

Java服务器/客户端套接字停止响应,java,sockets,Java,Sockets,我的客户机/服务器程序有问题。服务器应该从客户端获取一个文件,然后将其转换为xml,然后将xml文件流回到客户端 到目前为止,所有工作都可以将xml文件流式传输回客户端。我可以成功地将文件发送到服务器并将其转换为XML 服务器不向客户端发送任何内容。客户端卡在从InputStream读取字节的区域中。在Client类的第57行 公共类服务器{ 私有服务器套接字服务器套接字; 私有套接字clientSocket; 私人打印输出; 中的私有缓冲区读取器; 公共静态无效字符串[]args{ int端口

我的客户机/服务器程序有问题。服务器应该从客户端获取一个文件,然后将其转换为xml,然后将xml文件流回到客户端

到目前为止,所有工作都可以将xml文件流式传输回客户端。我可以成功地将文件发送到服务器并将其转换为XML

服务器不向客户端发送任何内容。客户端卡在从InputStream读取字节的区域中。在Client类的第57行

公共类服务器{ 私有服务器套接字服务器套接字; 私有套接字clientSocket; 私人打印输出; 中的私有缓冲区读取器; 公共静态无效字符串[]args{ int端口=8081; 服务器srv=新服务器端口; } 公共服务器INT端口号{ 试一试{ serverSocket=新的ServerSocketportNumber; clientSocket=serverSocket.accept; out=新的PrintWriterClient socket.getOutputStream,true; //in=新的缓冲读取器 //新建InputStreamReaderClient socket.getInputStream; byte[]myArray=新字节[22000];//应为文件大小 InputStream为=clientSocket.getInputStream; FileOutputStream fos=新的FileOutputStreamfile.csv; BufferedOutputStream bos=新的BufferedOutputStreamfos; int字节读取; int电流=0; bytesRead=is.readmyArray,0,myArray.length; 当前=字节读取; 做{ bytesRead=is.readmyArray,current,myArray.length-current; 如果字节读取>=0 电流+=字节读取; }而字节读取>-1; bos.writemyArray,0,myArray.length; bos.flush; 布尔标志=假; System.out.printlnServer:已完成接收文件; XMLWriter xmlWrite=新的XMLWriter; xmlWrite.createXmlDocumentfile_copy.csv; sendXMLserver_file.XML; clientSocket.close; System.out.printlnServer:与客户端断开连接; }捕捉异常{ //TODO自动生成的捕捉块 e、 打印跟踪; }捕获异常e{ //TODO自动生成的捕捉块 e、 打印跟踪; } } 公共void sendXMLString文件名{ System.out.println发送文件; File File=新文件名; 缓冲数据流bis; 试一试{ FileInputStream fis=新的FileInputStreamfile; bis=新的缓冲数据流FIS; DataInputStream dataIn=新的DataInputStream bis; OutputStream outStream=clientSocket.getOutputStream; 整数长度; 试一试{ 长度=dataIn.readInt; System.out.printlnS:+dataIn.readInt; 字节[]数据=新字节[长度]; dataIn.readFullydata,0,data.length; }捕捉异常{ //TODO自动生成的捕捉块 e、 打印跟踪; } }捕获文件NotFoundException e1{ //TODO自动生成的捕捉块 e1.printStackTrace; }捕获IOE1异常{ //TODO自动生成的捕捉块 e1.printStackTrace; } } 公共类客户端{ 专用插座主插座; 公共静态无效字符串[]args{ int端口=8081; 客户端cli=新客户端端口; } 公共客户端端口号{ 试一试{ mainSocket=新的Socketlocalhost,端口号; //将文件发送到服务器 File File=new FilePassengers.csv; FileInputStream fis=新的FileInputStreamfile; BufferedInputStream bis=新的BufferedInputStreamfis; OutputStream outStream=mainSocket.getOutputStream; 字节[]myBytes=新字节[int file.length]; bis.readmyBytes,0,myBytes.length; outStream.writemyBytes,0,myBytes.length; 流出;冲洗; System.out.printlnClient:发送文件完成; 字节[]文件数据=新字节[30000]; InputStream=mainSocket.getInputStream; FileOutputStream fos=新的FileOutputStreamclient_file.XML; BufferedOutputStream bos=新的BufferedOutputStreamfos; DataOutputStream dataOut=新的DataOutputStream bos; dataOut.writeInt fileData.length; dataOut.write文件数据; }捕捉异常{ //TODO自动生成的捕捉块 e、 打印跟踪; } } }
此循环将一直运行,直到流关闭,而不是直到客户端完成数据发送

do {
    bytesRead = is.read(myArray, current, (myArray.length - current) );
    if (bytesRead >= 0)
        current += bytesRead;
} while (bytesRead > -1);
这是因为InputStream.read将阻塞,直到至少有一个字节的数据可用或流关闭,从而导致返回-1。由于客户端已完成发送数据,但流仍处于打开状态,因此将永久阻塞

解决方案 n是首先使用类似于/的方式发送前4个字节中的文件长度,然后让客户机准确地发送那么多字节,服务器在继续之前准确地读取那么多字节

客户:

// Connect to the server and read in file data
byte[] fileData = ...;
DataOutputStream dataOut = new DataOutputStream( outStream );
dataOut.writeInt( fileData.length );
dataOut.write( fileData );
// Get reply from server
服务器:

// Create ServerSocket and get Client connection
DataInputStream dataIn = new DataInputStream( is );
int length = dataIn.readInt();
byte[] data = new byte[ length ];
dataIn.readFully( data );
// Continue to process client connection
这种网络通信背后的一般思想是,每个数据块或数据包在发送之前都会以其长度作为前缀。这意味着数据的接收者可以读入这个数字,并确切地知道还有多少字节可以形成完整的块或数据包。对于连接的双方,通信都是这样进行的。唯一的区别在于如何处理数据

public byte[] readPacket( DataInputStream dataIn ) throws IOException {
    int length = dataIn.readInt();
    byte[] packet = new byte[ length ];
    dataIn.readFully( packet );
    return packet;
}

public void writePacket( DataOutputStream dataOut, byte[] packet ) throws IOException {
    dataOut.writeInt( packet.length );
    dataOut.write( packet );
}

只有你会从某种循环中调用它们,最好是在后台线程上,但这不是你想要做的事情所必需的。对于您的情况,您希望在客户端将文件读入字节[],然后使用writePacket将其发送到服务器。在服务器端,您可以使用readPacket从客户端读取文件。将数据发送回客户端时也会发生同样的情况,但角色已切换。

服务器是否打印'System.out.printlnServer:disconnected with client;`?不,在我终止客户端之前,服务器不会打印任何内容。然后打印所有的东西。客户机在等待服务器时遇到阻碍,服务器什么也不做,直到我强制终止客户机。谢谢,这解决了大部分问题。现在,我在dataIn.readFullydata行上收到一个EOFEException。请确保客户端至少发送长度字节,并且您使用的是writeInt,而不是write。我是否应该先发送长度,然后继续按照原来的方式发送?我更新了代码以显示它现在的功能。问题不在于将XML发送回客户端的代码,而是将原始数据发送到服务器。您替换了服务器向客户端发送数据的部分。因此,在尝试发送实际数据之前,我想先执行datainputstream/dataoutputstream。