java的socket网络编程

代码并没有报错运行的时候却一直报异常

package homework;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class homework {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket=new ServerSocket(9999);
        Socket socket=serverSocket.accept();//服务器
        BufferedInputStream bufferedInputStream = new BufferedInputStream(
                socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
        String destfilepath="src\\hello.txt";
        BufferedOutputStream bos = new BufferedOutputStream(new
                FileOutputStream(destfilepath));
        bos.write(bytes);
        bos.close();
        bufferedInputStream.close();
        socket.close();
        serverSocket.close();


    }

}

package homework;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class homework01 {
    public static void main(String[] args) throws Exception {
        //客户端
        Socket socket=new Socket(InetAddress.getLocalHost(),9999);
        String filepath="d:\\hello.txt";
        BufferedInputStream bufferedInputStream = new BufferedInputStream(
                new FileInputStream(filepath));
        //bytes就是filepath对应的的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
        //发送给服务器
        BufferedOutputStream bos = new BufferedOutputStream(
                socket.getOutputStream());
        bos.write(bytes);//将对应的文件写入服务器端
        bufferedInputStream.close();
        socket.shutdownOutput();//设置写入数据结束的标志
bos.close();
        socket.close();

    }
}
package homework;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
    /**
     * 功能:将输入流转换成byte[]
     * @param is
     * @return
     * @throws Exception
     */
    public static byte[] streamToByteArray(InputStream is) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
        byte[] b = new byte[1024];
        int len;
        while((len=is.read(b))!=-1){
            bos.write(b, 0, len);    
        }
        byte[] array = bos.toByteArray();
        bos.close();
        return array;
    }
    /**
     * 功能:将InputStream转换成String
     * @param is
     * @return
     * @throws Exception
     */
    
    public static String streamToString(InputStream is) throws Exception{
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder builder= new StringBuilder();
        String line;
        while((line=reader.readLine())!=null){
            builder.append(line+"\r\n");
        }
        return builder.toString();
        
    }

}


总是报这样的错请问什么毛病

"C:\Program Files\Java\jdk1.8.0_192\bin\java.exe" "-javaagent:D:\IntelliJ IDEA Community Edition 2021.3.2\lib\idea_rt.jar=38584:D:\IntelliJ IDEA Community Edition 2021.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_192\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_192\jre\lib\rt.jar;D:\IntelliJ IDEA Community Edition 2021.3.2\java\notemessage\out\production\notemessage" homework.homework01
Exception in thread "main" java.net.SocketException: Cannot send after socket shutdown: socket write error
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
    at homework.homework01.main(homework01.java:23)

Process finished with exit code 1


不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/235002
  • 你也可以参考下这篇文章:java的socket读取一行就结束运行了?使用这种方法可以读取多行数据!
  • 除此之外, 这篇博客: java的socket编程服务端一直收不到客户端信息中的 问题 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    服务端一直收不到客户端的信息,我很奇怪,因为我前几天做实验的时候,客户端和服务端是都能互相接收信息的,怎么到这里就不行了?

    以下是Client的问题代码:

    package com.jie.code05.client.service;
    
    import javafx.scene.control.Button;
    import javafx.scene.control.TextField;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class Client {
    
        public void connect(Button sendMessageButton, TextField homeMessage) {
            try (
                    Socket socket = new Socket("localhost", 9527);
                    // 发送信息
                    PrintWriter writer = new PrintWriter(socket.getOutputStream())
            ) {
                // 发信息
                sendMessageButton.setOnAction(event -> {
                    System.out.println("发送");
                    writer.write(socket.getLocalSocketAddress().toString().substring(1) + "  " + homeMessage.getText() + "\r\n");
                    writer.flush();
                });
                
            } catch (IOException e) {
                System.out.println("客户端发送信息失败...");
                e.printStackTrace();
            }
        }
    
    }
    

    因为是要求做图形化,所以我就在这里打开连接并且设置按钮,然后再去做其他事情。问题就出在这里,因为我使用的打开连接是在try的括号中的,而在括号中打开的各种流都会在执行完try中的代码块自动关闭而不用在finally中关闭,我贪图方便几乎所有的打开流都这样做,这里也直接复制了。最终在try中设置完按钮以后这个try的代码块就结束了,Socket也会自动帮我关掉,所以服务端才一直收不到客户端的信息。

    以下是修改过后的代码:

    package com.jie.code05.client.service;
    
    import javafx.scene.control.Button;
    import javafx.scene.control.TextField;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class Client {
    
        public void connect(Button sendMessageButton, TextField homeMessage) {
            Socket socket;
            PrintWriter writer;
            try {
                socket = new Socket("localhost", 9527);
                writer = new PrintWriter(socket.getOutputStream());
                // 发信息
                sendMessageButton.setOnAction(event -> {
                    System.out.println("发送");
                    writer.write(socket.getLocalSocketAddress().toString().substring(1) + "  " + homeMessage.getText() + "\r\n");
                    writer.flush();
                });
            } catch (IOException e) {
                System.out.println("客户端发送信息失败...");
                e.printStackTrace();
            }
        }
    
    }
    
    
  • 您还可以看一下 肖海鹏老师的Java8深入分析课程中的 socket项目演示小节, 巩固相关知识点
  • 以下回答来自chatgpt:

    这种情况很有可能是由于客户端没有正常关闭导致的,因为在Server这个类中的ClientThread这个线程内部处理完客户端请求后并没有发送一条消息通知客户端结束连接,导致客户端一直在等待读取信息,而服务端执行完线程之后无法再次读取客户端的信息。因此,客户端连接的关闭应该在服务端连接的关闭之前。可以在Client这个客户端类中的SeverThread里面判断是否已经关闭连接,如果已经关闭,则退出while循环。具体的解决方案如下:

    private class SeverThread implements Runnable {
    
        @Override
        public void run() {
            // 读取服务端发送的内容
            try {
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in, "UTF-8");
                BufferedReader br = new BufferedReader(isr);
    
                while (!socket.isClosed()) {    // 判断连接是否关闭
                    String message = br.readLine();
                    if (message != null) {
                        System.out.println(message);
                    }
                }
            } catch (ConnectException e) {
                System.out.println("服务器未启动,请稍后连接!");
            } catch (SocketException e) {
                System.out.println("服务器已中断,请重试!");
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("与服务器连接已关闭!");
        }
    
    }
    

    然后在Server这个类中,在finally块里面加上socket.close()即可。注意关闭socket的代码不能放在while中,而是放在最后的finally块中,否则会导致一些奇怪的问题,例如服务端无法接收客户端的消息、客户端也无法接收到服务端返回的消息等。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^