Socket学习

作者: 大数据阶梯之路 | 来源:发表于2019-07-25 20:04 被阅读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

    相关文章

      网友评论

        本文标题:Socket学习

        本文链接:https://www.haomeiwen.com/subject/zhbfrctx.html