美文网首页程序员
Java网络编程(1)

Java网络编程(1)

作者: iwen大大怪 | 来源:发表于2019-08-21 19:44 被阅读0次

    1.基本网络概念

    网络

    --网络是相互发送和接受数据的计算机和其他设备的集合;
    --每一个设备就是一个网络节点(node);
    --每一个计算机是一个主机(host)
    --每个网络节点有地址;
    --以太网分配物理地址;
    --Internet服务器分配Internet地址;
    --地址可以有标识名字,但是不与地址锁定;

    IP、TCP和UDP

    IP地址网络中计算机的唯一标识
    --P地址是用一个点来分成四段的,在计算机内部IP地址是用四个字节来表示的,一个字节代表一段,每一个字节代表的数最大只能到达255。
    --IPv4地址,4字节地址,例如192.168.6.190
    --包的首部保护目的地址和源地址
    --IPv4地址已经用完,目前在向IPv6地址过渡
    --IPv6地址,16字节地址,例如FEDC:7654:3210:FEDC:BA98:7654:3210
    域名(DNS)
    --用于记忆主机名,并在使用时转换为ip地址
    --IP地址会随着时间变换
    --127.0.0.1表示本地回送地址
    --IPv6的本地回送地址为::1
    端口正在运行的程序的标识。
    --每台计算机有65535个端口
    --1到1023保留给已知服务

    端口.png
    客户/服务器模型
    --服务端发送数据,客户端接收数据
    --对等端通过服务器程序实现相互通信
    TCP
    建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低
    --面向连接
    --安全可靠
    --效率稍低
    --通过三次握手确保连接的建立
    --举例:下载,打电话,QQ聊天(你在线吗,在线,就回应下,就开始聊天了)
    UDP
    将数据源和目的封装成数据包中,不需要建立连接;每个数据报的大小在限制在64k;因无连接,是不可靠协议;不需要建立连接,速度快
    --面向无连接
    --不可靠
    --速度快
    --将数据封包传输,数据包最大64k
    --举例:聊天留言,在线视频,视频会议,发短信,邮局包裹

    网络通信三要素

    IP地址:网络中设备的标识,不易记忆,可用主机名
    端口号:用于标识进程的逻辑地址,不同进程的标识
    传输协议(通讯的规则):常见协议:TCP,UDP

    URL

    URI=URL+URN
    URI:Uniform Resource Identifier ,统一资源标志符。
    URL:Uniform Resource Locator,统一资源定位符。
    URN:Uniform Resource Name,统一资源命名。

    TCP编程

    --TCP是可靠的连接,TCP就像打电话,需要先打通对方电话,等待对方有回应后才会跟对方继续说话,也就是一定要确认可以发信息以后才会把信息发出去。TCP上传任何东西都是可靠的,只要两台机器上建立起了连接,在本机上发送的数据就一定能传到对方的机器上。
    实例1
    服务器端

    //模拟服务器端
    class Service {
        public static void main(String[] args) throws IOException {
            //创建服务器端 表明自己端口号8989
            ServerSocket ss = new ServerSocket(8989);
            //一旦有客户端来链接 就获取客户端的socket
            Socket clientSocket = ss.accept();
            //向客户端发送数据
            //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
            //bw.write("登陆成功");
            PrintStream ps = new PrintStream(clientSocket.getOutputStream());
            ps.println("登陆成功");
    
            //输出完毕 关掉输出流
            clientSocket.shutdownOutput();
    
            //-----接收客户端发送的数据---//
            BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    
            String line = null;
            while ((line = br.readLine() )!= null){
                System.out.println(line);
            }
    
        }
    }
    

    客户端

    //模拟客户端
    class Client{
        public static void main(String[] args) throws IOException {
            //1.创建用于通信的Scoket
            // 指明和谁通信:ip地址 端口号
            Socket socket = new Socket("127.0.0.1",8989);
            //接收服务器的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //向服务器发送数据
            //socket.getOutputStream();
            //读取数据
            String line = null;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
            //---客户端向服务器发送数据---//
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("你好啊!");
            socket.shutdownOutput();
        }
    }
    

    执行结果:


    $FERE4RRV4E4}{SURXG)7ZX.png

    ![(UOO0B%@KH7%I1W3{4]09`Q.png](https://img.haomeiwen.com/i18945157/f927ea0e7a64e06d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    在上面结果可以看出,服务器与客户端都进行了数据的交换
    实例2

    /**
     * 手动输入内容发送
     * 客户<--> 1.文本 2.图片 3.视频 4.音频 <-->服务器端
     */
    /**----模拟客户端----*/
    class MyClient {
        public static void main(String[] args) {
            //链接服务器端的socket
            Socket socket =null;
            try {
                socket = new Socket("127.0.0.1",8989);
    
                //接收服务端发送的数据
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                //从键盘输入的数据 发送给服务器
    
                String line = null;
                while ((line = br.readLine()) != null){
                    System.out.println(line);
                }
            } catch (IOException e) {
                System.out.println("链接出错");
            }finally {
                //关闭链接
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**----模拟服务器端----*/
    class MyServer {
        public static void main(String[] args) {
            //创建ServerSocket
            try(ServerSocket ss = new ServerSocket(8989)){//在括号里面会自动释放
                //监听客户端链接
                Socket socket = ss.accept();
    
                //从终端接收数据
                BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
                //创建向客户端输出的输出流
                PrintStream ps = new PrintStream(socket.getOutputStream());
                String line = null;
    
                while ((line = keyin.readLine()) != null){
                    //调用刚刚创建的客户端输出流 发送信息给客户端
                    ps.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    上面程序执行的结果是:服务端可以从键盘输入数据,在发送给客户端
    实例3

    package day13media;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 客户端向服务器端上传图片
     */
    
    public class MyClass {
    }
    /**----模拟客户端----*/
    class Client{
        public static void main(String[] args) throws IOException {
            //链接服务器端 获取socket
            Socket socket = new Socket("127.0.0.1",8989);
            //创建服务器端对应的输入流 用于接收服务器端发送过来的数据
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println(br.readLine());
            //向服务器端发送图片
            //1.将文件写入到内存
            String path ="C://Users//18168//Desktop//yz.jpg";
            FileInputStream fis = new FileInputStream(path);
            //创建一个输出流
            BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
            byte[] buf = new byte[1024];
            int len = -1;
            while((len = fis.read(buf)) != -1){
                //开始向输出流中写入数据
                bos.write(buf,0,len);
            }
            socket.shutdownOutput();
        }
    }
    /**----模拟服务器端----*/
    class Server{
        public static void main(String[] args) throws IOException {
            //创建服务器端的serverSocket
            ServerSocket ss = new ServerSocket(8989);
            //监听客户端的链接,一但有客户端来链接就能得到socket,如果没有客户端来链接,服务器就会一直等待
            Socket socket = ss.accept();
            //创建客户端对应的输出流 用于向客户端发送数据
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println("链接成功,可以发送数据!");
    
            //接收客户端传递过来的图片 就是接上面客户端的输出流
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            //文件对应的输出流  也就是将获取的数据保存
            String path ="C://Users//18168//AndroidStudioProjects//java3//Java3//src//main//java//day13media/yz1.jpg";
            //创建写入的对象 并且指定要写入的路径
            FileOutputStream fos = new FileOutputStream(path);
            byte[] buf = new byte[1024];
            int len = -1;
            while ((len = bis.read(buf)) != -1){
                //开始写数据
                fos.write(buf,0,len);
            }
        }
    }
    

    执行结果:在对应的目录下有一张名字为:yz1.ipg的图片
    实例4
    --创建群聊,用一台电脑当服务器,其他电脑通过服务器的ip链接服务器,就可以实现多人聊天,这个实例涉及到多线程

    package group;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    
    /**
     * 群聊天
     * 1.在服务器端维护一个数组【socket】
     * 客户端和服务器端都可以随意的发送内容
     * 2.客户端:
     *      主线程:接收终端输入 将终端输入的数据发送给服务器
     *      子线程:接收来自服务器端发送的数据
     * 3.服务器端:
     *      主线程:接收终端输入 将终端输入的数据发送给客户端
     *      子线程:接收来自客户端发送的数据
     */
    
    /**----创建服务器端主线程----*/
    class Server{
        //保存每一个链接过来的对象
        public static ArrayList<Socket> sockets = new ArrayList<>();
    
        public static void main(String[] args) throws IOException {
            ServerSocket ss = new ServerSocket(8989);
    
            //不停的等待客户端的链接
            while (true) {
                Socket socket = ss.accept();
                //当有客户端链接过来就保存
                sockets.add(socket);
    
                //开启一个线程处理每个客户端的输入
                new ServerThread(socket).start();
            }
    
        }
    }
    /**----创建服务器端子线程----*/
    class ServerThread extends Thread {
        private Socket socket;
    
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
    
        @Override
        public void run() {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String lint = null;
                while ((lint = br.readLine()) != null) {
                    //群发消息
                    //遍历Server维护的数组
                    for (Socket s:Server.sockets) {
                        //向socket对应的客户发送消息
                        PrintStream ps = new PrintStream(s.getOutputStream());
                        ps.println(lint);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (br != null) {
                        //为了不浪费资源,要将流关闭
                        br.close();
                    }
                    if (socket != null) {
                        //为了不浪费资源,要将流关闭
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /**----模拟客户端----*/
    class Client{
        public static void main(String[] args) throws IOException {
            //这里指明服务器的ip地址和端口号
            Socket socket = new Socket("10.129.28.253",6666);
    
            //用一个子线程处理服务器端的数据
            new Thread(new ClientThread(socket)).start();
    
            //主线程处理终端输入并且给服务器发送
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;
            while ((line = keyin.readLine()) != null){
                ps.println(line);
            }
    
        }
    }
    /**----创建客户端子线程----*/
    class ClientThread implements Runnable{
        private Socket socket;
    
        public ClientThread(Socket socket){
            this.socket = socket;
        }
        @Override
        public void run() {
            //为了使finally能使用到这个,将其的作用域扩大
            BufferedReader br = null;
            try {
                //获取服务器输入流对象
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line = null;
                while ((line = br.readLine()) != null){
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (br != null){
                        //为了不浪费资源,要将流关闭
                        br.close();
                    }
                    if (socket != null){
                        //为了不浪费资源,要将流关闭
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    这个例子还有很多需要完善的地方,后期再慢慢更新!

    感悟

    学到这里慢慢的感觉java的乐趣来了,不再是那些枯燥的类与继承,而是一些比较好玩的编程,虽然看似简单,可是后面这些再也不是单一的知识点,而是要将前面学习的很多东西联系起来!

    相关文章

      网友评论

        本文标题:Java网络编程(1)

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