miracle just wanna be better

网络编程socket

2019-07-23
miracle

tcp编程:tcp传输控制协议,能够保证在数据传递不丢失
udp编程:不保证数据能够传递到对象,数据可能丢失

一些名词解释

  • socket套接字
  • ip地址 :用于确定网络上的计算机 ipv4 4段地址
    ipv6 6段地址
  • 端口号: 每台计算机都有65536个端口 0-65535
    能够访问计算机的”门”
    特殊的内置端口:
    • 80端口:http协议的默认端口 超文本传输协议
    • 21端口:ftp协议的默认端口 文件传输协议
    • 25端口:smtp协议的默认端口 邮件传输协议
  • tcp/ip:传输控制协议/网络协议

socket套接字

用于描述ip地址和端口号,是一个通讯链的句柄(java的引用)
在internet上的一个主机,一般运行多少个服务软件,同时就提供多少个服务,每个服务监听一个端口,不同的端口,对应不同的服务,最终应用程序和服务器通过socket套接字建立网络连接,发送请求和接受请求

服务端套接字

ServerSocket类

  • Socket accetp();
    用于监听并接受到套接字的连接
  • void close();
    关闭socket
  • InetAddress getInetAddress()
    返回自服务器套接字的本地地址
  • int getLocalport()
    返回此套接字在其上的监听的端口号

    客户端套接字

    Socket类

  • Socket(String host,int port);
    创建一个套接字并将其连接到指定的ip地址,和这个ip地址对应的端口号
  • void socket()
    关闭socket
  • InetAddress getInetAddress()
    返回自服务器套接字的本地地址
  • int getLocalport()
    返回此套接字在其上的监听的端口号

例子一

下载器例子

Client.java(客户端)

/**
 * 客户端:
 * 1.连接服务端
 * 2.从键盘输入服务器计算机中的文件路径,并请求下载
 * 3.如果服务端有文件,就返回给客户端文件的名称和文件长度
 * 4.从网络上获取服务器下载的文件数据,进入客户端的内存
 * 5.把内存的数据写到客户端的硬盘上
 */
public class Client {
    public static void main(String[] args)throws IOException {

        Scanner input = new Scanner(System.in);
        //创建socket对象(ip地址,端口号),连接服务器
        Socket socket = new Socket("10.8.38.123",9991);
        //构架网络输入输出流
        //网络输入流
        DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        //网络输出流
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        //从客户端获取网络上传递过来的字符串

        System.out.println("请输入服务端中的文件的路径");
        String filePath = input.next();
        //把文件路径发送到网络流
        dos.writeUTF(filePath);
        dos.flush();
        //接收文件的名字
        String fileName = dis.readUTF();

        //接收文件的长度
        String length = dis.readUTF();
        //输出
        System.out.println("文件在服务端存在,文件名为:"+fileName+" 文件长度:"+length);

        //从网络流上接收文件数据,并存储到内存,把内存数据输出到本地硬盘
        System.out.println("开始接收文件...");
        //构建本地流输出
        DataOutputStream dos_local = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("D:/aa/"+fileName)));
        //构建缓冲
        byte[] buffer = new byte[1024*4];//服务端和客户端缓冲大小一样
        //循环从网络流中读入数据进内存
        while(true){
            int len = -1;
            if(dis!=null){
                //从网络上读数据
                len = dis.read(buffer);
                dos_local.write(buffer,0,len);
            }
            if(len==-1){
                break;
            }
        }
        dos_local.close();
        dis.close();
        dos.close();
        socket.close();
        System.out.println("接收文件完毕,文件路径d:/aa" +fileName+" 文件大小"+length);
    }
}

Server.java(服务器)

/**
 * 服务端:给客户端提供服务
 * 1.接收客户端发送过来的文件路径,并判断文件是否存在
 * 2.获取文件的名称和文件的长度,并写到网络上
 * 3.从本服务器硬盘读取文件内容到内存
 * 4.把内存的文件数据写到网络上
 *
 * 一次只能给一个客户端提供服务
 */
public class Server {
    public static void main(String[] args) throws Exception {

        //创建了一个ServerSocket对象
        ServerSocket ss = new ServerSocket(9991);
        System.out.println("服务器已经启动");
        while (true) {
            Socket socket = ss.accept();
            //仅代表run逻辑
            ThreadHandler th = new ThreadHandler(socket);
            Thread t = new Thread(th);
            t.start();


        }

    }
}

ThreadHandler.java(线程控制器)

/**
 * 这个run任务逻辑,要给很多个socket提供服务
 */
public class ThreadHandler implements Runnable {
    private Socket socket;
    public ThreadHandler(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        //获取客户端的ip地址
        InetAddress ip = socket.getInetAddress();
        try {
            //构架网络输入输出流
            //网络输出流
            Scanner input = new Scanner(System.in);
            OutputStream os = socket.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream dos = new DataOutputStream(bos);
            //网络输入流
            DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

            String filePath = dis.readUTF();
            File file = new File(filePath);
            if (!file.exists()){
                dos.writeUTF("您请求的文件不存在,请换其他文件");
                dos.flush(); //清除缓冲,标记数据写出完毕,此时才将数据发送到网络上
                return;
            }
            //能到此处说明文件存在
            //获取文件的名称
            String fileName = file.getName();
            dos.writeUTF(fileName);
            dos.flush();
            //获取文件的长度
            long length = file.length();
            dos.writeUTF(length+"");
            dos.flush();
            //准备开始发送文件
            System.out.println(ip.getHostAddress()+"  fileName="+fileName+"  length="+length);
            System.out.println(ip.getHostAddress()+"  开始发送文件...");
            //从本地读取文件到内存中(本地流)
            DataInputStream dis_local = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            byte[] buffer = new byte[1024*4];
            while(true){
                int len = -1;
                if(dis_local!=null){
                    //本地流输入

                }
                if (len==-1){
                    break;
                }
                len = dis_local.read(buffer);
                dos.write(buffer,0,len);
            }
            dos.flush();
            dos.close();
            bos.close();
            os.close();
            dis.close();
            socket.close();//关闭套接字
            System.out.println(ip.getHostAddress()+"  文件:"+fileName+"发送完毕");
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

例子二

对话例子

Client.java(客户端)

/**
 * 客户端:
 * 1.连接服务端
 * 2.从键盘录入字符串,并发送给服务端
 * 3.接收服务端发送给客户端的数据并显示
 */
public class Client {
    public static void main(String[] args)throws IOException {

        Scanner input = new Scanner(System.in);
        //创建socket对象(ip地址,端口号),连接服务器
        Socket socket = new Socket("10.8.38.123",9991);
        //构架网络输入输出流
        //网络输入流
        DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        //网络输出流
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        //从客户端获取网络上传递过来的字符串

        System.out.println("请输入给服务端发送的数据");
        String sendMessage = input.next();
        dos.writeUTF(sendMessage);
        dos.flush();//清空缓冲区,写出数据到网络上
        String message = dis.readUTF();
        System.out.println("服务端回馈的数据:"+message);

        dis.close();
        dos.close();
        socket.close();

    }
}

Server.java(服务端)

/**
 * 服务端:给客户端提供服务
 * 1.接收客户端发送的字符串并显示
 * 2.从键盘录入一个字符串,并返回给客户端
 *
 * 一次只能给一个客户端提供服务
 */
public class Server {
    public static void main(String[] args) throws Exception {

        //创建了一个ServerSocket对象
        ServerSocket ss = new ServerSocket(9991);
        System.out.println("服务器已经启动");
        while (true) {
            Socket socket = ss.accept();
            //仅代表run逻辑
            ThreadHandler th = new ThreadHandler(socket);
            Thread t = new Thread(th);
            t.start();


        }

    }
}

ThreadHandler.java(线程控制器)

/**
 * 这个run任务逻辑,要给很多个socket提供服务
 */
public class ThreadHandler implements Runnable {
    private Socket socket;
    public ThreadHandler(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //构架网络输入输出流
            //网络输出流
            Scanner input = new Scanner(System.in);
            OutputStream os = socket.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream dos = new DataOutputStream(bos);
            //网络输入流
            DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));

            //从客户端获取网络上传递过来的字符串
            String message = dis.readUTF();
            System.out.println("客户端的信息:"+message);
            System.out.println("请输入给客户端的信息");
            String sendMessage = input.next();
            dos.writeUTF(sendMessage);//消息没有发送到网络上,写到本地计算机的缓冲中
            dos.flush();//清除缓冲,标记数据写出完毕,此时才将数据发送到网络上
            dos.close();
            bos.close();
            os.close();
            dis.close();
            socket.close();//关闭套接字
        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

上一篇 多线程之卖票

下一篇 线程池

Comments

Content