网络应用主要分为客户端和服务端,在Java中Socket类是处理客户端通信的类,通过这类可以连接到指定IP或域名的服务器,从而实现客户端与服务端互相发送接收数据。

使用Socket传输文件

在使用套接字进行编码时,有时需要通过Socket传输文件。下面例子实现Socket多线程从客户端向服务端传输文件。

Server关键代码:

public class Server extends ServerSocket {
public Server() throws Exception {// 构造方法
    super(1998); //端口号
}
public void transfer() throws Exception {
while (true) {
//接收其他Socket的连接请求、accept方法是阻塞式
       Socket socket = this.accept(); 
// 当接收到Socket请求,创建新的线程来处理
        new Thread(new multitask(socket)).start();
    }
}
//线程类(用于处理客户端传过来的文件) 
class multitask implements Runnable {
// 省略了对Socket、DataInputStream、FileOutputStream声明的代码
    public multitask(Socket socket) {
        this.socket = socket;
    }
@Override
    public void run() {
        try {//获取输入流对象
dis = new DataInputStream(socket.getInputStream()); 
            File directory = new File("D:\\new_Html.zip");
 // 可对directory目录进行判断是否存在,不存在则创建,已省略部分不关键的代码
out = new FileOutputStream(file); 
            byte[] bytes = new byte[1024]; //定义字节数组
            int length = 0;
            while((length = dis.read(bytes, 0, bytes.length)) != -1) {//读取
out.write(bytes, 0, length);
out.flush();
            }
            System.out.println("接收成功);
        } catch (Exception e) {
e.printStackTrace();
        } finally {
//省略了关闭资源的代码
        }
    }
}
}
Client(客户端关键代码)
public void transferFiles() throws Exception {
        try {
            File file = new File("D:/html网页.zip");// 实例化File对象
            if(file.exists()) {
fis = new FileInputStream(file);
dos = new DataOutputStream(client.getOutputStream()); 
dos.writeUTF(file.getName());//文件名
dos.flush();
dos.writeLong(file.length());// 将文件大小写入输出流
dos.flush(); 
                byte[] bytes = new byte[1024];
                int length = 0;
                long progress = 0;
                while((length = fis.read(bytes, 0, bytes.length)) != -1) {
dos.write(bytes, 0, length); //将字节数组写入输出流
dos.flush();
//省略部分非关键代码
                }
                 System.out.println("传输成功");
            }
        } catch (Exception e) {
e.printStackTrace();
        } finally {
// 省略了关闭资源的代码
        }
    }

上面代码主要通过使用DataInputStream类的read()方法将文件读取到字节数组,然后使用DataOutputStream类从DataOutput类继承的write方法输出字节数组,从而实现传输文件。

 

 

DataInputStream

read()方法,该方法可以将文件中的信息读取到字节数组

public final int read(byte[] b ) b为存储读取到信息的字节数组

write()方法,该方法可以输出字节数组

void write(byte[] b) b为需要写入输出流中的字节数组

分别运行上面服务端和客户端的代码,效果如下

java 传递socket java socket接收数据_服务端

java 传递socket java socket接收数据_字节数组_02

使用Socket传输对象(客户端和服务端发送或接受的类对象)

首先创建一个类(对象类),该类需要实现java.io. Serializable接口,如下

public class Student implements Serializable {  // 序列化对象类
    private String studentNumber;                 
    private String studentName; 
// 省略了getter、setter方法
}

创建一个ServerFrame类继承JFrame窗体类,为该窗体类添加一个滚动面板控件,然后在该面板上添加一个JTextArea文本域控件(显示客户端与服务端互相发送的信息),再添加JPanel控件,在JPanel面板上添加两个标签以及文本框,为Student类创建的对象传递参数值 该类关键代码如下

public ServerFrame() {
        super();
//省略了添加控件等若干代码
        final JButton button = new JButton();
button.addActionListener(new ActionListener() {//监听按钮
            public void actionPerformed(final ActionEvent e) {
                Student stud = new Student();
stud.setStudentNumber(tf_id.getText());
stud.setStudentName(tf_name.getText());
                try {
out.writeObject(stud);
                } catch (IOException e1) {
e1.printStackTrace();
                } 
ta_info.append("服务器 studnetNumber:" + tf_id.getText() + "  studentName:"+tf_name.getText()+"\n"); // 将文本框中信息显示在文本域中
tf_id.setText(null); // 将文本框清空
tf_name.setText(null);
            }
        });
        final JPanel panels = new JPanel();
        getContentPane().add(panels, BorderLayout.SOUTH);
button.setText("发送");
panels.add(button);
    }

ServerFrame类的connectServer方法,该方法用于创建套接字、监听客户端以及创建向客户端发送信息的输出流对象、创建用于客户端发送信息的输入流对象,代码如下

public void createServer () {
        try {
server = new ServerSocket(1998); // 实例化Socket对象
            while (true) { 
ta_info.append("等待客户端连接....\n");
socket = server.accept(); // 实例化Socket对象
ta_info.append("客户端已连接\n"); 
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
                getClient(); // 调用getClient方法
            }
        } catch (Exception e) {
e.printStackTrace(); 
        }
    }

getClient()方法 ,该方法接收客户端发送过来的信息,代码如下

private void getClient() {
        try {
            while (true) { 
                Student student = (Student)in.readObject();//转为Student类型
                if (student!=null)
ta_info.append("客户端: StudentNumbe:" + student.getStudentNumber() + "StudentName:" + student.getStudentName() + "\n"); // 显示客户端发送过来信息
            }
        } catch (Exception e) {
ta_info.append("客户端已退出\n"); 
        } finally {
// 省略了关闭流以及套接字代码
        }
    }

在main主方法中创建本类实例,设置该类的窗体为可见,调用createServer方法

 

客户端:创建一个名为ClientFrame的类,继承Jframe类, 为该窗体类添加控件,具体跟上面的ServerFrame类大同小异,关键代码如下

该类构造方法如下,省略了创建JTextField、JLabel、JPanel等代码

public ClientFrame() { 
        super(); 
        setTitle("客户端");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds((width - windowsWedth) / 2,(height - windowsHeight) / 2, windowsWedth, windowsHeight); //居中显示
cc = this.getContentPane(); // 实例化对象
        final JScrollPane scrollPane = new JScrollPane();
        getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(ta_info);
        getContentPane().add(getPanel(), BorderLayout.NORTH);
        getContentPane().add(getButton(), BorderLayout.SOUTH); 
    }

连接套接字方法 创建Socket对象,参数分别是IP、端口号,然后再创建向服务端发送信息的输出流对象以及接收客户端发送的信息的输入流对象

private void connectServer() { // 连接套接字
ta_info.append("正在努力连接......\n"); 
socket = new Socket("192.168.43.56", 1998); // 实例化Socket对象
            while (true){
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
ta_info.append("连接成功\n"); // 文本域中显示连接成功信息
                getServerInfo ();//调用方法
            } 
    }

getServerInfo方法 该方法接收服务器传过来的信息

private void getServerInfo() {
        try {
            while (true) { 
                Student student = (Student)in.readObject();
                if (student!=null)
ta_info.append("服务器: studentNumber:" + student.getStudentNumber() + "StudentName:" +student.getStudentName() + "\n"); 
            }
        } catch (Exception e) {
e.printStackTrace();
        } 
        finally {
//省略了关闭资源的代码
        }
    }

在main主方法设置窗体可见,调用连接方法

public static void main(String[] args) { // 主方法
    ClientFrame clienFrame = new ClientFrame(); 
clienFrame.setVisible(true); // 将窗体显示
clienFrame.connectServer(); // 调用connectServer方法
    }

效果

java 传递socket java socket接收数据_服务端_03

小结:使用Socket传输对象的时候,该类必须是序列化的,也就是实现了Serializable接口