• 网络编程笔记


    目录

    udp传输基础示范:

    图形化的界面显示小Demo(udp):

    TCP传输笔记:

    客户端向服务器上传文件小Demo(tcp):


     

    关于Java TCP/IP Socket方面这位博主写得很详细也很全面:https://blog.csdn.net/ns_code/article/details/17526127

    udp传输基础示范:

    先用2个控制台窗口执行。

    先运行Demo2_Receive,再运行Demo2_Send,运行Demo2_Send发送消息能在另一个创建口接收到。

    效果如图:

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    
    public class Demo2_Receive {
        /**
         * 2.接收Receive 创建DatagramSocket, 指定端口号 创建DatagramPacket, 指定数组, 长度
         * 使用DatagramSocket接收DatagramPacket 关闭DatagramSocket 从DatagramPacket中获取数据
         * 3.接收方获取ip和端口号 String ip = packet.getAddress().getHostAddress(); int port =
         * packet.getPort();
         * 
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            DatagramSocket socket = new DatagramSocket(12233); // 创建Socket相当于创建一个码头
            DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); // 创建Packet相当于创建一个集装箱
            socket.setSoTimeout(10000); // 毫秒单位,10s
            int MAX_TIME = 5; // 最多超时5次
            boolean isReceive = false; // 是否已经接收到消息
            byte[] arr = null;
            int len = 0;
            String ip = null;
            int port = 0;
            int tries = 0;
            while (!isReceive && tries < MAX_TIME) {
    
                try {
                    socket.receive(packet);
    
                    arr = packet.getData();
                    len = packet.getLength();
                    ip = packet.getAddress().getHostAddress();
                    port = packet.getPort();
                    isReceive = true;
                    packet.setLength(1024); // 多线程这句一定要加
                } catch (Exception e) {
                    ++tries;
                    System.out.println("Time out," + (MAX_TIME - tries) + " more tries...");
                }
            }
            if (isReceive) {
                System.out.println(ip + ":" + port + ":" + new String(arr, 0, len));
            } else {
                System.out.println("No response -- give up.");
            }
        }
    }
    

     如果设置了接收超时方法setSoTimeout,超过时间仍没有接收到发送端发送的消息,没有处理异常,则抛出以下异常

    为了更人性化一点,需要处理异常,处理异常后效果如下:

    DatagramPacket的内部消息长度值在接收数据后会发生改变,变为实际接收到的数据的长度值。

    这里构造一个DatagramPacket用于接收缓冲区长度为1024数据包,这里写了接收一次的receive方法,如果有多个线程的receive方法,那么下一次packet接收到的消息值就只有上一次消息长度了,比如本来可以接收1024的长度的消息,上一次接收了200长度的消息,缓冲区由1024变成了200,下一次传输了666长度的消息,接收时后面的466长度消息将会丢失。为了避免这种情况。每次调用前就必须显式地将其内部消息长度重置为缓存区的实际长度,比如这里的packet.setLength(1024);以免接受的数据发生丢失。

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    
    public class Demo2_Send {
        /**
         * 1.发送Send
         * 创建DatagramSocket, 随机端口号
         * 创建DatagramPacket, 指定数据,长度,地址,端口
         * 使用DatagramSocket
         * 发送DatagramPacket 
         * 关闭DatagramSocket
         * 
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            DatagramSocket socket = new DatagramSocket();
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                String line = br.readLine();
                if ("quit".equals(line)) {
                    break;
                }
                byte[] b = line.getBytes();
                DatagramPacket packet = new DatagramPacket(b, b.length, InetAddress.getByName("127.0.0.1"), 12233);
                socket.send(packet);
            }
            socket.close();
            br.close();
        }
    }

    public class DatagramSocket extends Object

    此类表示用来发送和接收数据报包的套接字。

    数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。

    在 DatagramSocket 上总是启用 UDP 广播发送。为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。在某些实现中,将 DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。

    示例:DatagramSocket s = new DatagramSocket(null); s.bind(new InetSocketAddress(8888)); 这等价于:DatagramSocket s = new DatagramSocket(8888); 两个例子都能创建能够在 UDP 8888 端口上接收广播的 DatagramSocket。

    jdk1.8-api说明:http://blog.fondme.cn:8000/apidoc/jdk-1.8-google/

    点击右上角搜索即可

    public final class DatagramPacket extends Object

    该类表示数据报包。

    数据报包用于实现无连接分组传送服务。 仅基于该数据包中包含的信息,每个消息从一台机器路由到另一台机器。 从一台机器发送到另一台机器的多个分组可能会有不同的路由,并且可能以任何顺序到达。 包传送不能保证。

    public DatagramPacket(byte[] buf, int length)  // 两个参数构造用在接收端

    构造一个DatagramPacket用于接收长度的数据包length 。

    length参数必须小于或等于buf.length 。

    参数

    buf - 用于保存传入数据报的缓冲区。

    length - 要读取的字节数。

    ===========================================================

    public DatagramPacket(byte[] buf, int length, InetAddress address, int port)

    // 4个参数的构造方法用在发送端,更多构造请看官方文档。

    构造用于发送长度的分组的数据报包length指定主机上到指定的端口号。 length参数必须小于或等于buf.length 。

    参数

    buf - 分组数据。

    length - 包长度。

    address - 目的地址。

    port - 目的端口号。

    另请参见:

    InetAddress

    图形化的界面显示小Demo(udp):

    默认是127.0.0.1本地回路地址,如果清空什么都不填默认是255.255.255.255广播

    简单效果如图示:

    功能简介:

    下面是输入消息的对话框,上面是显示的对话框。

    按钮“发送”可以发送消息看得到本地的发送,也可以按快捷键Ctrl+Enter发送

    点击“清屏”可以清除对话框消息

    点击“聊天记录”可以加载出聊天记录,存在config.txt文件里,config.txt默认在该Demo的文件夹下,也就是假如这个Demo的名字是project,这个文件夹有bin,src...等目录,那么config.txt和它们同级,如图

    这里点击“震动”是给对方发送震动,本地并不会震动(为了效果我注释了本地震动代码),当然,环路测试会震动,广播也会震动,因为包括了自己。这里是可以自己给自己发送消息的。选择255.255.255.255(为空也默认是这个)发送,如图:

    也可以看到我的ip为192.168.164.1,如果我对这个ip点击震动,那么我的窗口会震动,因为是给自己发送,如果换成192.168.164.2,我的窗口就不会震动了,该那个ip的窗口震动了。

    如果这是两个人的对话,那么就只会显示xxx.xxx.xxx.xxx对我说:!@#¥%……&*

    这里只是给出udp通信的效果。

    import java.awt.BorderLayout;
    import java.awt.Button;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.Frame;
    import java.awt.Panel;
    import java.awt.TextArea;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.BufferedInputStream;
    import java.io.BufferedWriter;
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Demo4_GUI_Chat extends Frame {
    
        private TextArea viewText;
        private TextArea sendText;
        private TextField tf;
        private Button send;
        private Button clear;
        private Button log;
        private Button shake;
        private DatagramSocket socket;
        private BufferedWriter bw;
    
        public Demo4_GUI_Chat() throws IOException {
            southPanel();
            centerPanel();
            init();
            event();
        }
    
        private void event() {
            this.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosing(WindowEvent e) {
                    try {
                        socket.close();
                        bw.close();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                    System.exit(0);
                }
            });
            send.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        send();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            });
            clear.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    viewText.setText("");
                }
            });
            log.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    logFile();
                }
            });
            shake.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    // shake();// 自己是否振动
                    try {
                        send(new byte[] { -1 }, tf.getText());
                        // 这个-1是手动发不出去的,字符串-1是2个字符
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            });
            sendText.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    // 这个判断条件不要放在keyReleased(KeyEvent e)里面,否则不灵敏
                    if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) { // 如果是Ctrl+Enter
                        try {
                            send();
                        } catch (IOException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }
                    }
    
                    super.keyReleased(e);
                }
            });
        }
    
        private void shake() {
            // TODO Auto-generated method stub
            int x = this.getLocation().x;
            int y = this.getLocation().y;
    
            for (int i = 0; i < 5; ++i) {
                this.setLocation(x + 5, y);
                this.setLocation(x + 5, y + 5);
                this.setLocation(x, y + 5);
                this.setLocation(x - 5, y + 5);
                this.setLocation(x - 5, y);
                this.setLocation(x - 5, y + 5);
                this.setLocation(x, y - 5);
                this.setLocation(x + 5, y - 5);
                this.setLocation(x, y);
            }
        }
    
        private void logFile() {
            try {
                bw.flush(); // 点击记录才会刷到文件中,或者缓冲区满了自动刷
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream("config.txt"));
                ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 显示到控制台,不用字符流
                int len;
                byte[] arr = new byte[8192];
                while ((len = bis.read(arr)) != -1) {
                    baos.write(arr, 0, len);
                }
                bis.close();
                viewText.setText(baos.toString());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        private void send(byte[] arr, String ip) throws IOException {
            DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 8888);
            socket.send(packet);
        }
    
        private void send() throws SocketException, IOException {
            String ip = tf.getText();
            ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
            String message = sendText.getText(); // 获取信息
    
            send(message.getBytes(), ip);
            String time = getCurrentTime();
            String str = time + "我对" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "说:
    " + message + "
    "; // Alt+shift+l抽取局部变量
            viewText.append(str);
            bw.write(str);
            bw.flush();
            sendText.setText("");
        }
    
        private String getCurrentTime() {
            Date d = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
            return sdf.format(d);
        }
    
        private void centerPanel() {
            Panel center = new Panel();
            viewText = new TextArea();
            sendText = new TextArea(5, 1);
            center.setLayout(new BorderLayout()); // 改变了布局管理器
            viewText.setEditable(false); // 接受框不能编辑
            viewText.setBackground(Color.WHITE);
    
            viewText.setFont(new Font("xxx", Font.PLAIN, 15));
            sendText.setFont(new Font("yyy", Font.PLAIN, 20)); // 第一个参数设置字体无效,默认就一种字体
    
            center.add(sendText, BorderLayout.SOUTH);
            center.add(viewText, BorderLayout.CENTER);
    
            this.add(center, BorderLayout.CENTER);
        }
    
        private void southPanel() {
            Panel south = new Panel(); // 创建南边面板
            tf = new TextField(15);
            tf.setText("127.0.0.1");
            send = new Button("发 送");
            clear = new Button("清 屏");
            log = new Button("聊天记录");
            shake = new Button("震 动");
    
            south.add(tf);
            south.add(send);
            south.add(clear);
            south.add(log);
            south.add(shake);
            this.add(south, BorderLayout.SOUTH);
        }
    
        private void init() throws IOException {
            this.setSize(400, 600);
    
            this.setLocation(500, 50);
            this.setVisible(true); // 这句要放在后面,否则加载效果可能看不到
            socket = new DatagramSocket();
    
            bw = new BufferedWriter(new FileWriter("config.txt", true));
    
            new Receive().start();
        }
    
        private class Receive extends Thread {
            public void run() {
                try {
                    DatagramSocket socket = new DatagramSocket(8888);
                    DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
                    while (true) {
                        socket.receive(packet);
                        byte[] arr = packet.getData();
                        int len = packet.getLength();
                        if (arr[0] == -1 && len == 1) { 
                        // 汉字编码第一个是负数,第二个是正数,避免产生可能的意外,确定发送的只有一个字节并且第一个字符为-1,才是特殊的震动功能
                            shake();
                            continue;
                        }
                        String message = new String(arr, 0, len);
                        String time = getCurrentTime();
                        String ip = packet.getAddress().getHostAddress();
                        String str = time + " " + ip + " 对我说:
    " + message + "
    ";
                        viewText.append(str);
                        bw.write(str);
                        bw.flush();
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        public static void main(String[] args) throws IOException {
            new Demo4_GUI_Chat();
        }
    }
    void keyPressed(KeyEvent e)

    按下键时调用。

    void keyReleased(KeyEvent e)

    当键已被释放时调用。

    void keyTyped(KeyEvent e)

    键入键时调用。

    有不懂的可以复制某个方法直接百度,这就是用博客做笔记的好处,简单快捷。

    附录:

    将jar文件转换成exe可执行文件: 
    exe文件使用方便,而且还可以提高源码及资源的安全性,但同时也失去了java的初衷--跨平台性. 
    如果你坚持要转换成exe文件,请按以下方式进行: 
    利用exe4j这个软件转换jar文件为exe文件,exe4j下载地址:http://www.ej-technologies.com/download/exe4j/files.html,(目前最新版本为6)有的需要安装,有的只要解压缩即可用.我一般用安装的exe4j软件,它们没有什么区别,因此找个可以用的就行了.下载安装后,运行它,接着按步骤操作: 
    1.运行后直接点Next. 
    2.选择第二项“JAR in EXE mode”,之后点击Next. 
    3.在General---Short name of your application框中输入你的应用程序的名字(随便即可),在Directories---Output directory框中输入生成exe后的保存路径,然后Next. 
    4.在Excutable name框中输入将要生成的exe的名字,“Icon File”是应用程序显示的小图标,不选也行.这里选择环境Advanced Options为32-bitor64-bit,勾选generate 64-bit executable,继续Next. 直到Configure java invocation页面
    5.必须先配置Class-Path,点击右边+号添加文件,即jar文件,如果有用到其它资源需要把资源一起添加进去. 可以直接把目录复制粘贴进去。
    6.General --- Main Class选择主类. 
    7.Java Version --- Minimum version(低版本必须填写),Maximum version(高版本可以为空),如果都有填写那么高版本的值必须大于低版本的值. 
    8.勾选Allow JREs with a beta version number以及Only allow JDKs and no JREs.接着Next.到这一步你可以直接finish.这样就把jar转换成exe文件了.你可以点击Click Here to Start the Application按钮测试生成的文件.

    TCP传输笔记:

    效果图:

    代码如下:

    服务器端:

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Demo1_Server {
        /**
         * 2.服务端 创建ServerSocket(需要指定端口号), 调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket.
         * 调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流.
         * 输入流可以读取客户端输出流写出的数据, 输出流可以写出数据到客户端的输入流
         * 
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            // demo1();
            // demo2();
            ServerSocket server = new ServerSocket(9999); // 创建服务器
            System.out.println();
            while (true) { // 不断接受客户端请求
                // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
                final Socket socket = server.accept(); // 等待客户端连接,进入阻塞状态
                new Thread() {
                    public void run() {
                        try {
                            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 对输入流包装
                            PrintStream ps = new PrintStream(socket.getOutputStream()); // 对输出流包装
                            ps.println("我是服务器,你已经连接上我了,可以开始说话了"); // 向客户端写出数据
                            System.out.println("本地端口:" + socket.getLocalPort() + "
    客户端口:" + socket.getPort()
                                    + "
    远程连接地址:" + socket.getInetAddress().getHostAddress() + "
    本地地址:"
                                    + socket.getLocalAddress().getHostAddress());
                            System.out.println(br.readLine()); // 读取并打印
                            socket.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }.start();
    
            }
        }
    
        /*
         * private static void demo2() throws IOException { ServerSocket server = new
         * ServerSocket(9999); Socket socket = server.accept(); BufferedReader br = new
         * BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream
         * ps = new PrintStream(socket.getOutputStream()); ps.println("当然是我服务器先发第一句");
         * System.out.println(br.readLine()); socket.close(); }
         * 
         * private static void demo1() throws IOException { ServerSocket server = new
         * ServerSocket(9999); System.out.println("等待你的连接"); Socket socket =
         * server.accept(); System.out.println("连接成功"); InputStream is =
         * socket.getInputStream(); OutputStream os = socket.getOutputStream();
         * os.write("百度一下你就知道".getBytes()); byte[] arr = new byte[1024]; int len =
         * is.read(arr); System.out.println(new String(arr, 0, len));
         * os.write("服务器收到了,谢谢客户端".getBytes()); server.close(); socket.close(); }
         */
    }
    

    客户端: 

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class Demo1_Client {
        /**
         * 1.客户端 创建Socket连接服务器(指定ip地址,端口号)通过ip地址找对应的服务器
         * 调用Socket的getInputStream()和getOutputStream()方法获取和服务器端相连的IO流.
         * 输入流可以读取服务端输出流写出的数据,输出流可以写出数据到服务端的输入流
         * 
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            // demo1();
            Socket socket = new Socket("127.0.0.1", 9999); // 创建socket
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintStream ps = new PrintStream(socket.getOutputStream());
            System.out.println(br.readLine());
            System.out.println("客户端信息:
    " + "本地端口:" + socket.getLocalPort() + "
    服务器端口:" + socket.getPort()
                    + "
    远程连接地址:" + socket.getInetAddress().getHostAddress() + "
    本地地址:"
                    + socket.getLocalAddress().getHostAddress());
            BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
            ps.println(br1.readLine());
            br1.close();
            socket.close();
            // 关闭此套接字也将会关闭该套接字的 InputStream 和 OutputStream。
            // 如果此套接字有一个与之关联的通道,则关闭该通道
        }
    
        /*
         * private static void demo1() throws UnknownHostException, IOException { Socket
         * socket = new Socket("127.0.0.1", 9999); InputStream is =
         * socket.getInputStream(); OutputStream os = socket.getOutputStream(); byte[]
         * arr = new byte[1024]; int len = is.read(arr); System.out.println(new
         * String(arr, 0, len)); os.write("学习使我快乐,客户端收到。".getBytes());
         * 
         * byte[] arr2 = new byte[1024]; int len2 = is.read(arr2);
         * System.out.println(new String(arr2, 0, len2)); }
         */
    }

    public int getPort()

            返回此套接字连接到的远程端口。

    返回:此套接字连接到的远程端口号;如果尚未连接套接字,则返回 0。

    public int getLocalPort()

            返回此套接字绑定到的本地端口。

    返回:此套接字绑定到的本地端口号;如果尚未绑定套接字,则返回 -1。

    getInetAddress()是返回套接字连接的地址比如"127.0.0.1",返回的是一个InetAddress对象,调用getHostAddress()可以返回 IP 地址字符串(以文本表现形式)。比如“127.0.0.1”

    getLocalAddress()获取套接字绑定的本地地址。返回的是一个返回的是一个InetAddress对象,调用getHostAddress()可以返回 IP 地址字符串(以文本表现形式)。比如“127.0.0.1”

    记住转换成主机地址是getHostAddress不是getAddress(),getAddress()返回原始ip,但是我试了一下返回乱码,见官方文档。

    客户端向服务器上传文件小Demo(tcp):

    服务器端:

    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Test1_UploadServer {
        public static void main(String[] args) throws IOException {
            // 建立多线程的服务器
            ServerSocket server = new ServerSocket(12345);
            System.out.println("服务器启动,绑定12345端口号");
            while (true) {
                final Socket socket = server.accept();
                new Thread() {
                    public void run() {
                        try (InputStream is = socket.getInputStream();
                                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                                PrintStream ps = new PrintStream(socket.getOutputStream());) {
                            String fileName = br.readLine();
    
                            File dir = new File("Upload");
                            dir.mkdirs();
    
                            File file = new File(dir, fileName);
                            // 判断文件是否存在,将结果发回客户端
                            if (file.exists()) {
                                ps.println("存在");
                                return;
                            } else {
                                ps.println("不存在");
                            }
                            try ( // 定义FileOutputStream,从网络读取数据存储到本地
                                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));) {
                                byte[] arr = new byte[8192];
                                int len;
                                while ((len = is.read(arr)) != -1) {
                                    bos.write(arr, 0, len);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                socket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start();
            }
        }
    }

    客户端:

    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class Test1_UploadClient {
        public static void main(String[] args) throws IOException {
            // 提示输入要上传的文件路径,验证路径是否存在以及是否是文件夹
            File file = getFile();
            Socket socket = null;
            BufferedReader br;
            try {
                // 发送文件名到服务端
                socket = new Socket("127.0.0.1", 12345);
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                PrintStream ps = new PrintStream(socket.getOutputStream());
                ps.println(file.getName());
                // 接收结果,如果存在给予提示,程序直接退出
                String result = br.readLine();
                if ("存在".equals(result)) {
                    System.out.println("您上传的文件已经存在,请不要重复上传");
                    return;
                } else {
                    BufferedInputStream br2 = null;
                    try {
                        // 如果不存在,定义FileInputStream读取文件,写出到网络
                        br2 = new BufferedInputStream(new FileInputStream(file));
                        byte[] arr = new byte[8192];
                        int len;
                        // 先由BufferedInputStream读取到它的内存缓冲数组中,默认也是8192字节
                        // 再定义一个数组长度为8192字节,每次传输数组中的数据给服务器
                        while ((len = br2.read(arr, 0, 8192)) != -1) { // 尝试每次读取8192字节
                            ps.write(arr, 0, len); // len是实际读取到的字节,可能最后一次不到8192字节
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        br2.close();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                socket.close();
            }
        }
    
        /**
         * 获取文件路径
         */
        public static File getFile() {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("请输入有个文件路径:");
            while (true) {
                String line = null;
                try {
                    line = br.readLine();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                File file = new File(line);
                if (!file.exists()) {
                    System.out.println("文件不存在,重输:");
                } else if (file.isDirectory()) {
                    System.out.println("路径为文件夹,重输:");
                } else {
                    return file;
                }
            }
        }
    }

    如果是控制台窗口直接运行bin文件夹里面的包下的字节码文件,那么默认在binUpload目录下生成文件,也就是上传的文件在这里。

    如果是eclipse先运行服务器代码,再运行客户端代码,那么默认在当前项目下,比如项目名project, 那么就在projectUpload目录下生成文件,也就是上传到服务器的文件在这里。

    =================================Talk is cheap, show me the code===============================

    CSDN博客地址:https://blog.csdn.net/qq_34115899
  • 相关阅读:
    vi/vim系统编辑命令使用技巧
    C++基础之智能指针
    C++基础之volatile关键字
    C++基础之强制类型转换
    C++基础之左值、右值与移动语义
    C++基础之对象模型
    C++基础之运行时类型识别RTTI
    C++基础之指针与引用的底层实现
    深度学习之参数计算(CNN为例)
    数学基础之勾股数
  • 原文地址:https://www.cnblogs.com/lcy0515/p/10807889.html
Copyright © 2020-2023  润新知