moc 发表于 2019-1-14 20:09:17

Java033-网络编程

本帖最后由 moc 于 2019-8-29 21:02 编辑

1、简介
1. 网络编程含义:
       用Java语言实现计算机间数据的信息传递和资源共享。
2. 网络编程模型:
        ① OSI(Open System Interconnection开放系统互连)参考模型(7 层模型)
                应用层 》表示层 》会话层 》传输层 》网络层 》数据链路层 》物理层
        ② TCP/IP参考模型
                应用层 》传输层 》网际层 》链路层 》物理层
3. 网络编程三要素:
        ① IP地址
                》点分十进制记法,私有地址不在互联网上使用,用于局域网。
                》A类地址: 1.0.0.1—126.255.255.254   --- 保留给政府机构{10.X.X.X是私有地址}
                》B类地址:128.0.0.1—191.255.255.254--- 中等规模的公司{172.16.0.0—172.31.255.255是私有地址、169.254.X.X是保留地址}
                》C类地址:192.0.0.1—223.255.255.254--- 任何需要的人{192.168.X.X是私有地址}
                》D类地址:224.0.0.1—239.255.255.254
                》E类地址:240.0.0.1—255.255.255.254
                》127.X.X.X为保留地址,用做循环测试用的。
        ② 端口
                同一个主机内不同应用程序的标识,范围:0-65535。其中0-1024不建议使用。
        ③ 协议
                》TCP:建立数据通道,全双工,无边界流,效率低,面向连接,可靠
                》UDP:无数据通道,全双工,数据打包,效率高,无连接,不可靠
4. Socket机制
        ① 通信两端都应该有Socket对象;
        ② 客户端和服务器通过对 Socket 对象的写入和读取来进行通信;
2、UDP通讯
1. 相关API
InetAddress类: --- 互联网协议 (IP) 地址
public static InetAddress getByName(String host) ----> 在给定主机名的情况下确定主机的 IP 地址; 主机名可以是机器名,也可是其 IP 地址的文本表示形式。
public String getHostName()---------------------------->获取此 IP 地址的主机名。
public String getHostAddress() -------------------------->返回 IP 地址字符串(文本表现形式)。
DatagramSocket类: --- 表示用来发送和接收数据报包(UDP)的套接字
public DatagramSocket()----------------------------------- -->构造数据报套接字并将其绑定到本地主机上任何可用的端口。
public DatagramSocket(int port)----------------------------->创建数据报套接字并将其绑定到本地主机上的指定端口,IP 地址由内核选择。
public DatagramSocket(int port, InetAddress laddr) ------>创建数据报套接字,将其绑定到指定的本地地址。
public void receive(DatagramPacket p)--------------------->从此套接字接收数据报包。
public void send(DatagramPacket p) ------------------------>从此套接字发送数据报包。
DatagramPacket类: --- 表示数据报包,用来实现无连接包投递服务。
public DatagramPacket(byte[] buf, int length)------------>构造 DatagramPacket,用来接收长度为 length 的数据包。
public DatagramPacket(byte[] buf, int length, InetAddress address, int port)-----> 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
public InetAddress getAddress()----------------------------->返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
public byte[] getData()    -------------------------------------->   返回将要发送或接收到的数据缓冲区内容。
public int getLength()------------------------------------------>返回将要发送或接收到的数据的长度。
2. UDP协议发送数据
步骤:
        ① 创建发送端Socket对象;
        ② 创建数据,并把数据打包;
        ③ 调用Socket对象的发送方法发送数据包;
        ④ 释放资源。
public class UdpSendDemo {
        public static void main(String[] args) throws IOException {
                // 创建发送端Socket对象
                DatagramSocket ds = new DatagramSocket();

                // 创建数据,并把数据打包
                byte[] bys = "UDP,你好!".getBytes();// 创建数据
                int length = bys.length;// 长度
                InetAddress address = InetAddress.getByName("192.168.12.92");// IP地址对象
                int port = 10086;        // 端口
                DatagramPacket dp = new DatagramPacket(bys, length, address, port);

                // 调用Socket对象的发送方法发送数据包
                ds.send(dp);

                // 释放资源
                ds.close();
        }
}3. UDP协议接受数据
步骤:
        ① 创建接收端Socket对象;
        ② 创建一个数据包(接收容器);
        ③ 调用Socket对象的接收方法接收数据;
        ④ 解析数据包,并显示在控制台;
        ⑤ 释放资源。
public class UdpReceiveDemo {
        public static void main(String[] args) throws IOException {
                // 创建接收端Socket对象
                DatagramSocket ds = new DatagramSocket(10086);

                // 创建一个数据包(接收容器)
                byte[] bys = new byte;
                int length = bys.length;
                DatagramPacket dp = new DatagramPacket(bys, length);

                // 调用Socket对象的接收方法接收数据
                ds.receive(dp); // 阻塞式

                // 解析数据包,并显示在控制台
                InetAddress address = dp.getAddress();// 获取对方的ip
                String ip = address.getHostAddress();
                byte[] bys2 = dp.getData();   // 获取数据缓冲区
                int len = dp.getLength();   // 获取数据的实际长度
                String s = new String(bys2, 0, len);
                System.out.println(ip + "传递的数据是:" + s);

                // 释放资源
                ds.close();
        }
}4. 多线程结合收发UDP数据包
// ***********发送UDP数据报类
public class UdpSendThread implements Runnable {
        private DatagramSocket ds;
        public SendThread(DatagramSocket ds) {
                this.ds = ds;
        }

        @Override
        public void run() {
                try {
                        // 封装键盘录入数据
                        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                        String line = null;
                        while ((line = br.readLine()) != null) {
                                if ("886".equals(line)) {
                                        break;
                                }

                                // 创建数据并打包
                                byte[] bys = line.getBytes();
                                DatagramPacket dp = new DatagramPacket(bys, bys.length,
                                                                        InetAddress.getByName("192.168.12.255"), 12306);

                                // 发送数据
                                ds.send(dp);
                        }

                        // 释放资源
                        ds.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}
// ***********接受UDP数据报类
public class ReceiveThread implements Runnable {
        private DatagramSocket ds;
        public ReceiveThread(DatagramSocket ds) {
                this.ds = ds;
        }

        @Override
        public void run() {
                try {
                        while (true) {
                                // 创建一个包裹
                                byte[] bys = new byte;
                                DatagramPacket dp = new DatagramPacket(bys, bys.length);

                                // 接收数据
                                ds.receive(dp);

                                // 解析数据
                                String ip = dp.getAddress().getHostAddress();
                                String s = new String(dp.getData(), 0, dp.getLength());
                                System.out.println("from " + ip + " data is : " + s);
                        }
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}
// ***********测试类
public class ChatRoom {
        public static void main(String[] args) throws IOException {
                DatagramSocket dsSend = new DatagramSocket();
                DatagramSocket dsReceive = new DatagramSocket(12306);

                SendThread st = new SendThread(dsSend);
                ReceiveThread rt = new ReceiveThread(dsReceive);

                Thread t1 = new Thread(st);
                Thread t2 = new Thread(rt);

                t1.start();
                t2.start();
        }
}3、TCP通讯
1. 相关API
Socket类: --- TCP客户端套接字
public Socket(InetAddress address, int port) --------> 创建一个流套接字并将其连接到指定 IP 地址的指定端口号
public InetAddress getInetAddress()----------------->返回套接字连接的地址。
public InputStream getInputStream()---------------->返回此套接字的输入流。
public OutputStream getOutputStream()------------>返回此套接字的输出流。
public void shutdownOutput()-------------------------->   通知对方套接字写入结束。
ServerSocket类: --- TCP服务器套接字
public ServerSocket(int port)-------------------------->创建绑定到特定端口的服务器套接字。
public Socket accept() ---------------------------------->侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
2. TCP客户端实现
步骤:
        ① 创建发送端的Socket对象;
        ② 这一步如果成功,就说明连接已经建立成功;
        ③ 获取输出流写数据,获取输入流读数据 ;
        ④ 释放资源;
以下以客户端向服务器上传文件为例:
注意:
        读取文本文件时可以以null作为结束信息的,TCP流通道不能以null结束;
        于是① 自定义结束标记;
              ② Socket对象提供了一种解决方案,public void shutdownOutput()
public class UdpUploadClient {
       public static void main(String[] args) throws IOException {
                // 创建客户端Socket对象
                Socket s = new Socket("192.168.12.92", 11111);

                // 封装文本文件
                BufferedReader br = new BufferedReader(new FileReader("123.txt"));
                // 封装通道内流
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

                String line = null;
                while ((line = br.readLine()) != null) { // 阻塞
                        bw.write(line);
                        bw.newLine();
                        bw.flush();
                }
                //自定义一个结束标记
                //bw.write("over");
                //bw.newLine();
                //bw.flush();
               
                //Socket提供了一个终止,它会通知服务器:客户端数据传输已结束
                s.shutdownOutput();

                // 接收反馈
                BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
                String client = brClient.readLine();   // 阻塞
                System.out.println(client);

                // 释放资源
                br.close();
                s.close();
        }
}3. TCP服务器实现
步骤:
        ① 创建接收端的Socket对象;
        ② 监听客户端连接。返回一个对应的Socket对象;
        ③ 获取输出流写数据,获取输入流读数据 ;
        ④ 释放资源。
public class UploadServer {
        public static void main(String[] args) throws IOException {
                // 创建服务器端的Socket对象,并绑定端口
                ServerSocket ss = new ServerSocket(11111);

                // 监听客户端连接
                Socket s = ss.accept(); // 阻塞

                // 封装通道内的流
                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                // 封装文本文件
                BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));

                String line = null;
                while ((line = br.readLine()) != null) { // 阻塞
                        // if("over".equals(line)){   // 采用自定义“over”结束符
                        // break;
                        // }
                        bw.write(line);
                        bw.newLine();
                        bw.flush();
                }

                // 给出反馈
                BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                bwServer.write("文件上传成功");
                bwServer.newLine();
                bwServer.flush();

                // 释放资源
                bw.close();
                s.close();
        }
}4. TCP服务器多线程实现并发
支持服务器能够被多个客户端连接。
// **********服务器线程类
public class UserUdpThread implements Runnable {
        private Socket s;
        public UserUdpThread (Socket s) {
                this.s = s;
        }

        @Override
        public void run() {
                try {
                        // 封装通道内的流
                        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
                        // 封装文本文件
                        // BufferedWriter bw = new BufferedWriter(newFileWriter("Copy.txt"));

                        // 为了防止名称冲突
                        String newName = System.currentTimeMillis() + ".txt";
                        BufferedWriter bw = new BufferedWriter(new FileWriter(newName));

                        String line = null;
                        while ((line = br.readLine()) != null) { // 阻塞
                                bw.write(line);
                                bw.newLine();
                                bw.flush();
                        }

                        // 给出反馈
                        BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                        bwServer.write("文件上传成功");
                        bwServer.newLine();
                        bwServer.flush();

                        // 释放资源
                        bw.close();
                        s.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}
// **********服务器
public class UploadUdpServer {
        public static void main(String[] args) throws IOException {
                // 创建服务器Socket对象
                ServerSocket ss = new ServerSocket(11111);

                while (true) {
                        Socket s = ss.accept();
                        new Thread(new UserUdpThread(s)).start();
                }
        }
}

ALWAYS浩然 发表于 2019-5-28 21:24:51

{:10_257:}

琴长不过时光 发表于 2019-6-26 20:06:09

不错的内容 能写多一点就好了

erh 发表于 2019-8-27 21:07:53

public class UserUdpThread implements Runnable {
        private Socket s;
        public UserThread(Socket s) {
                this.s = s;
        }

构造函数拼写错误l

moc 发表于 2019-8-29 21:03:12

erh 发表于 2019-8-27 21:07
public class UserUdpThread implements Runnable {
        private Socket s;
&#1 ...

谢谢提醒,已修正。
页: [1]
查看完整版本: Java033-网络编程