Java学习之IO流操作中的小坑

Java学习之IO流操作中的小坑

最近在写一个基于Socket的聊天室,部分内容如下:将一个对象以对象流的形式从客户端发送到服务端,在服务端解接收对象并打印内容。怎么样,是不是很简单,没错,就是这么简单的东西硬是花了我两个小时改bug。。。

先定义1个对象类User


package com.common;

public class User implements java.io.Serializable {

    private String uid;
    private String pwd;

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public User(String uid, String pwd) {
        this.uid = uid;
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid='" + uid + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

然后是客户端代码

package com.server.model;

import com.client.view.FriendList;
import com.common.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class TestClient {
    public static void main(String[] args) {
        try {
            Socket client = new Socket("localhost",9999);
            ObjectOutputStream output = new ObjectOutputStream(client.getOutputStream());
            ObjectInputStream input = new ObjectInputStream(client.getInputStream());
            User u = new User("111","aaa");
            output.writeObject(u);
            System.out.println("OK");//发送之后输出“OK”
        } catch (IOException e) {
            System.out.println("客户端连接失败");
            e.printStackTrace();
        }
    }
}

接着是服务器代码

package com.server.model;

import com.common.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TestServer {
    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(9999);
            //2.阻塞式等待客户端连接  (返回值)Socket accept()侦听要连接到此套接字的客户端并接受它。
            Socket client = server.accept();
            System.out.println("一个客户端已连接....");
            ObjectInputStream input = new ObjectInputStream(client.getInputStream());
            ObjectOutputStream output = new ObjectOutputStream(client.getOutputStream());
            User u = (User) input.readObject();
            System.out.println(u.toString());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败!");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

其实很简单,创建一个uid=111,pwd="aaa"的对象,发送到服务器,输出“OK”,服务器接收对象并调用其toString()方法输出,但结果是客户端能连接到服务器,之后就没有然后了,也就是说服务器端只输出了“一个客户端已连接”,并没有接收到客户端发来的数据,客户端也没有输出“OK”,这我就郁闷了,明明能连接上,为什么就发不过去呢,我尝试换了个端口号,结果还是这样。

可能有人会说,你客户端只是发送数据为什么要获取输入流,你服务器只是接收数据为什么要获取输出流,其实实际情况是客户端之后会接收数据,服务器也会会用客户端数据,只是被我把这部分代码注释了,但这也给了我一个思路,既然没用,不如去掉,没想到,这去掉之后真的直接成功了。

经过一系列尝试改进之后,我发现服务器端不用删代码也能成功,真正的问题是客户端这两行代码的先后问题,

ObjectOutputStream output = new ObjectOutputStream(client.getOutputStream());
ObjectInputStream input = new ObjectInputStream(client.getInputStream());

我觉得这有点扯淡,但事实就是这样,当input语句在output语句之后执行时,没有任何问题,但是顺序颠倒就是失败,试了好几次都是这样,我不知道这是什么原因,但还是觉得记下来比较好,万一哪天又碰到这种奇葩问题,就能解决了。

最后说一句,我在写完这篇博客后又去试了一次把input语句放在output语句之前,没想到啊没想到,这次竟然成功了,我都想摔了了这电脑了,看了看写了这么长的博客,唉,还是算了吧,不删了,希望大家看完之后不要打我,我先溜了,有什么想法可以留言,哈哈哈哈。。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://vivi.run/archives/java学习之io流操作中的小坑----基于socket的客户端和服务器端通信