Java 杂谈

Socket学习

2019-07-25  本文已影响5人  大数据阶梯之路

一、什么是Socket编程

Socket是进程通讯的一种方式,即调用这个网络库的一些API函数实现分布在不同主机的相关进程之间的数据交换。socket网络编程主要分为两部分,一个是ServerSocket服务端,一个是Socket客户端,socket网络编程主要就是用这2个类。

二、Socket网络编程入门Demo

代码思路流程:服务端先开启服务,然后等待客户端请求连接,发送和接收消息都是通过io流来实现。

Server.java

package socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args){
        try {
            //开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
            ServerSocket server = new ServerSocket(9999);
            System.out.println("开启服务...等待连接");
            //等待客户端连接,判断是否有客户端来进行连接
            Socket socket = server.accept();
            System.out.println("与客户端连接成功");
            //给客户端发送消息
            OutputStream outputStream = socket.getOutputStream();
            String message = "hello";
            outputStream.write(message.getBytes());

            //接收客户端发送来的消息
            InputStream inputStream = socket.getInputStream();
            byte[] bs = new byte[100];
            inputStream.read(bs);
            System.out.println("接收来自客户端的消息:"+new String(bs));

            //关闭流
            outputStream.close();
            inputStream.close();
            socket.close();
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client.java

package socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args){
        try {
            Socket socket = new Socket("127.0.0.1",9999);
            //接收服务端的消息
            InputStream inputStream = socket.getInputStream();
            byte[] bs = new byte[100];
            //inputStream读到的字节输入到那里去
            inputStream.read(bs);
            //把字节数组转换为字符串输出
            System.out.println("接收来自服务端的消息:"+new String(bs));

            //发送给服务端消息
            OutputStream outputStream = socket.getOutputStream();
            String message = "我是小江";
            outputStream.write(message.getBytes());

            //关闭流
            outputStream.close();
            inputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
程序运行截图: image.png image.png

三、socket网络编程发送接收文件

代码思路:建立连接这些还是和之前发送接收字符串的一样,变化的是在发送部分的代码上,上面发送字符串可以直接发送,因为变量是存在内存中的,计算机可以直接获取到,而我们文件是存放在本地硬盘的,所以我们要想办法把文件也放到内存中。
硬盘-->内存(相当于发送):直接new一个InputStream,因为不是用来网络请求所以不需要使用socket来获取,同理,内存-->硬盘(相当于接收):直接new一个OutputStream。
服务端发送文件时,通过不断地从硬盘读文件的字节到内存中,存在字节数组里,然后通过socket输出流发送给客户端,客户端接收文件时,通过不断地从内存的字节数组里读取,然后通过socket输入流写入到硬盘中。

Server.java

package socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args){
        try {
            //开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
            ServerSocket server = new ServerSocket(9999);
            System.out.println("开启服务...等待连接");
            //等待客户端连接,判断是否有客户端来进行连接
            Socket socket = server.accept();
            System.out.println("与客户端连接成功");

            //准备要发送的文件
            File file = new File("D:\\设计模式 (状态).pdf");
            //从硬盘读取到内存中
            InputStream fileIn = new FileInputStream(file);
            //用于网络发送文件
            OutputStream outputStream = socket.getOutputStream();
            int len = -1;//传输结束标识
            byte[] bs = new byte[1000];//字节缓冲区,每次发送的文件大小100个字节
            //循环发送(因为文件一般会大,超过100字节,所以需要循环来分次发送)
            while((len=fileIn.read(bs))!=-1){
                outputStream.write(bs,0,len);
            }
            //关闭流
            fileIn.close();
            outputStream.close();
            socket.close();
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client.java

package socket;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args){
        try {
            Socket socket = new Socket("127.0.0.1",9999);
            //从内存中读取到硬盘中
            OutputStream outputStream = new FileOutputStream("E:\\www.txt");
            //用于网络接收文件
            InputStream inputStream = socket.getInputStream();
            int len = -1;//传输结束标识
            byte[] bs = new byte[1000];//字节缓冲区
            //循环写入
            while ((len = inputStream.read(bs))!=-1){
                outputStream.write(bs,0,len);
            }
            //关闭流
            outputStream.close();
            inputStream.close();
            socket.close();
            System.out.println("下载成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、对上述程序使用线程进行优化

经过第二点的程序,我们能实现一次发送文件的功能,相当于客户端下载一次服务端的文件,但是我们现在想法是要实现开启服务器,然后我们客户端可以无限下载服务器的文件,我们可以使用循环来做,并且用多线程控制多个请求。通过构造方法把服务端的socket对象拿到。附重构后的代码:

Download.java(线程类,专门用来run事情处理下载功能)

package socket;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Download implements Runnable{

    private Socket socket;
    public Download(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //准备要发送的文件
            File file = new File("D:\\设计模式 (状态).pdf");
            //从硬盘读取到内存中
            InputStream fileIn = new FileInputStream(file);
            //用于网络发送文件
            OutputStream outputStream = socket.getOutputStream();
            int len = -1;//传输结束标识
            byte[] bs = new byte[1000];//字节缓冲区,每次发送的文件大小100个字节
            //循环发送(因为文件一般会大,超过100字节,所以需要循环来分次发送)
            while ((len = fileIn.read(bs)) != -1) {
                outputStream.write(bs, 0, len);
            }
            //关闭流
            fileIn.close();
            outputStream.close();
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Server.java

package socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args){
        try {
            //开启服务,绑定服务端口,默认为本机IP地址+下面传进来的端口号
            ServerSocket server = new ServerSocket(9999);
            System.out.println("开启服务...等待连接");
            int i = 1;
            while (true){
                //等待客户端连接,判断是否有客户端来进行连接
                Socket socket = server.accept();
                System.out.println("与客户端第"+(i++)+"次连接成功");
                //下载的线程,Runnable对象不能直接start,所以要Runnable-->Thread对象
                new Thread(new Download(socket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client.java(这个程序是可以发到其他电脑去执行的,更改下服务端IP地址即可到指定IP地址的服务器去下载文件,不过前提是服务器的程序服务有开启先。)

package socket;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args){
        try {
            Socket socket = new Socket("127.0.0.1",9999);
            //从内存中读取到硬盘中
            OutputStream outputStream = new FileOutputStream("E:\\设计模式 (状态)copy.pdf");
            //用于网络接收文件
            InputStream inputStream = socket.getInputStream();
            int len = -1;//传输结束标识
            byte[] bs = new byte[1000];//字节缓冲区
            //循环写入
            while ((len = inputStream.read(bs))!=-1){
                outputStream.write(bs,0,len);
            }
            //关闭流
            outputStream.close();
            inputStream.close();
            socket.close();
            System.out.println("下载成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

附程序截图(前面3次是我自己本地电脑测试,后面2次是我把客户端程序发给朋友电脑,我自己开服务端程序,然后让他更改IP地址到我这台服务端下载文件,经测试均成功)

image.png
附:1、socket编程网络知识1
2、socket编程网络知识2
上一篇下一篇

猜你喜欢

热点阅读