Java基础学习第三十天(网络编程、IP、端口号、UDP协议、TCP协议)

一、网络编程

1、网络编程: 网络编程主要用于解决计算机与计算机(手机、平板..)之间的数据传输问题。

2、区分网络编程和网页编程
① 网络编程不需要基于html页面就可以达到数据之间的传输。 比如: feiQ , QQ , 微信….
② 网页编程就是要基于html页面的基础上进行数据的交互的。 比如: 珍爱网、 oa(办公自动化)、 高考的报告系统…

3、计算机网络: 分布在不同地域的计算机通过外部设备链接起来达到了消息互通、资源共享的效果就称作为一个计算机网络。

4、网络通讯的三要素:IP、端口号、协议

二、IP地址

1、IP地址:IP地址的本质就是一个由32位的二进制数据组成的数据。后来别人为了方便我们记忆IP地址,就把IP地址切成了4份,每份8bit。2^8 = 0~255
00000000-00000000-00000000-00000000

2、IP地址 = 网络号+ 主机号。

3、IP地址的分类
① A类地址 = 一个网络号 + 三个主机号 2^24 政府单位
② B类地址 = 两个网络号 + 两个主机号 2^16 事业单位(学校、银行..)
③ C类地址 = 三个网络号 + 一个主机号 2^8 私人使用

4、常用的方法

方法 解释
getLocalHost() 获取本机的IP地址
getByName(“IP或者主机名”) 根据一个IP地址的字符串形式或者是一个主机名生成一个IP地址对象。 (用于获取别人的IP地址对象)
getHostAddress() 返回一个IP地址的字符串表示形式。
getHostName() 返回计算机的主机名
public class Demo30.1{
    public static void main(String[] args) throws UnknownHostException {
        //getLocalHost 获取本机的IP地址对象
        InetAddress address = InetAddress.getLocalHost();
        System.out.println("IP地址:"+address.getHostAddress());
        System.out.println("主机名:"+address.getHostName());   

        //获取别人机器的IP地址对象
        //可以根据一个IP地址的字符串形式或者是一个主机名生成一个IP地址对象。
        InetAddress address = InetAddress.getByName("Jolly-pc140116");
        System.out.println("IP地址:"+address.getHostAddress());
        System.out.println("主机名:"+address.getHostName());   

        InetAddress[]  arr = InetAddress.getAllByName("www.baidu.com");//域名 
    }
}

三、端口号

1、端口号是没有类描述的。

2、端口号的范围: 0~65535
① 从0到1023:系统紧密绑定于一些服务
② 1024~65535:我们可以使用

四、UDP协议

1、网络通讯的协议:
① udp通讯协议
② tcp通讯协议。

2、UDP的特点
① 将数据极其源和目的封装为数据包,不需要建立连接。
② 每个数据包大小限制在64K中
③ 因为无连接,所以不可靠
④ 因为不需要建立连接,所以速度快
⑤ udp 通讯是不分服务端与客户端的,只分发送端与接收端。
如:对讲机、飞秋、凌波、CS等

3、在java中网络通讯也称作为Socket(插座)通讯,要求通讯的两台机器都必须要安装Socket,不同的协议就有不同的插座(Socket)。

4、udp协议下的Socket
① DatagramSocket:udp插座服务
② DatagramPacket:数据包类
③ DatagramPacket(buf, length, address, port):{buf:发送的数据内容、length:发送数据内容的大小、address:发送的目的IP地址对象、port:端口号}

5、发送端的使用步骤
① 建立udp的服务
② 准备数据,把数据封装到数据包中发送。 发送端的数据包要带上ip地址与端口号
③ 调用udp的服务,发送数据
④ 关闭资源

//发送端
public class Sender {
    public static void main(String[] args) throws IOException {
        //建立udp的服务
        DatagramSocket datagramSocket = new DatagramSocket();
        //准备数据,把数据封装到数据包中。
        String data = getData("这个是我第一个udp的例子..");
        //创建了一个数据包
        //每个网络程序都有自己所处理的特定格式数据,如果接收到的数据不符合指定的格式,那么就会被当成垃圾数据丢弃(加密)
        DatagramPacket packet = new DatagramPacket(data.getBytes(), data.getBytes().length,InetAddress.getLocalHost(), 9090);
        //在udp协议中有一个IP地址称作为广播地址,广播地址就是主机号为255地址。给广播IP地址发送消息的时候,在同一个网络段的机器都可以接收到信息(192.168.15.255)
        //DatagramPacket packet = new DatagramPacket(data.getBytes(), data.getBytes().length,InetAddress.getName("192.168.15.255"), 2425);          
        //调用udp的服务发送数据包
        datagramSocket.send(packet);
        //关闭资源:实际上就是释放占用的端口号
        datagramSocket.close();     
    }

    // 把数据拼接成指定格式的数据
    //version:time :sender : ip: flag:content ;
    //版本号   时间   发送人  :IP:发送的标识符(32): 真正的内容;
    public static String getData(String content) {
        StringBuilder sb = new StringBuilder();
        sb.append("1.0:");
        sb.append(System.currentTimeMillis() + ":");
        sb.append("狗蛋:");
        sb.append("192.168.10.1:");
        sb.append("32:");
        sb.append(content);
        return sb.toString();
    }
}

6、接收端的使用步骤
① 建立udp的服务
② 准备空的数据包接收数据。
③ 调用udp的服务接收数据。
④ 关闭资源

public class Receive {
    public static void main(String[] args) throws IOException {
        //建立udp的服务,并且要监听一个端口。
        DatagramSocket socket = new DatagramSocket(9090);   
        //准备空的数据包用于存放数据
        byte[] buf = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length); // 1024
        //调用udp的服务接收数据
        socket.receive(datagramPacket); //receive是一个阻塞型的方法,没有接收到数据包之前会一直等待,数据实际上就是存储到了byte的字节数组中了。
        System.out.println("接收端接收到的数据:"+ new String(buf,0,datagramPacket.getLength())); // getLength()获取数据包存储了几个字节
        //关闭资源
        socket.close(); 
    }
}

7、群聊

//群聊发送端
public class ChatSender extends Thread {
    @Override
    public void run() {
        try {
            //建立udp的服务
            DatagramSocket socket = new DatagramSocket();
            //准备数据,把数据封装到数据包中发送
            BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            DatagramPacket packet = null;
            while((line = keyReader.readLine())!=null){
                //把数据封装到数据数据包中,然后发送数据。
                packet = new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("192.168.15.255"), 9090);
                //把数据发送出去
                socket.send(packet);
            }
            //关闭资源
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//群聊接收端
public class ChatReceive extends Thread {
    @Override
    public void run() {
        try {
            //建立udp的服务,要监听一个端口
            DatagramSocket socket = new DatagramSocket(9090);
            //准备空的数据包存储数据
            byte[] buf = new byte[1024];
            DatagramPacket packet = new DatagramPacket(buf, buf.length);
            boolean flag = true;
            while(flag){
                socket.receive(packet);
                // packet.getAddress() 获取对方数据 包的IP地址对象。         System.out.println(packet.getAddress().getHostAddress()+"说:"+new String(buf,0,packet.getLength()));
            }
            //关闭资源
            socket.close(); 
        }catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class ChatMain { 
    public static void main(String[] args) {
        ChatReceive chatReceive = new ChatReceive();
        chatReceive.start();    
        ChatSender chatSender = new ChatSender();
        chatSender.start(); 
    }
}

8、udp是一个不可靠(数据包可能会丢失)的协议
什么情况下数据包会出现丢失呢?带宽不足、cpu的处理能力不足

public class SafeSender{
    public static void main(String[] args) throws Exception {
        //建立udp的服务
        DatagramSocket socket = new DatagramSocket();
        //准备数据,数据封装到数据中发送
        DatagramPacket packet = null;
        for(int i =  0 ; i< 10; i++){  //连续发送10个数据包
            String data =i +"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            packet = new DatagramPacket(data.getBytes(), data.getBytes().length, InetAddress.getLocalHost(), 9090);
            //发送数据包
            socket.send(packet);
        }
        //关闭资源
        socket.close();
    }
}
public class SafeReceive {
    public static void main(String[] args) throws IOException, Exception {
        //建立udp的服务
        DatagramSocket socket = new DatagramSocket(9090);   
        //建立空的数据包存储数据
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);    
        //不断接收数据包
        while(true){
            socket.receive(packet);
            System.out.println(new String(buf,0,packet.getLength()));
            Thread.sleep(10);
        }   
    }
}

五、TCP协议

1、TCP的特点
① tcp是基于IO流进行数据的传输的,面向连接
② tcp进行数据传输的时候是没有大小限制的
③ 通过三次握手机制连接,可靠协议
④ 通信前必须建立连接,效率稍低
⑤ tcp是区分客户端与服务端的。
如:打电话、文件的传送

2、tcp协议下的Socket
Socket(客户端) ,tcp的客户端一旦启动马上要与服务端进行连接。

3、tcp的客户端使用步骤:
① 建立tcp的客户端服务
② 获取到对应的流对象
③ 写出或读取数据
④ 关闭资源

//tcp客户端
public class Clinet {   
    public static void main(String[] args) throws IOException{
        //建立tcp的服务
        Socket socket  = new Socket(InetAddress.getLocalHost(),9090);
        //获取到Socket的输出流对象
        OutputStream outputStream = socket.getOutputStream();
        //利用输出流对象把数据写出即可。
        outputStream.write("服务端你好".getBytes());     
        //获取到输入流对象,读取服务端回送的数据。
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int length = inputStream.read(buf);
        System.out.println("客户端接收到的数据:"+ new String(buf,0,length));     
        //关闭资源
        socket.close();     
    }
}
//服务端
public class Server {
    public static void main(String[] args) throws Exception {
        //建立Tcp的服务端,并且监听一个端口。
        ServerSocket serverSocket = new ServerSocket(9090);
        //接受客户端的连接
        Socket socket  =  serverSocket.accept(); //accept()接受客户端的连接 该方法也是一个阻塞型的方法,没有客户端与其连接时,会一直等待下去。
        //获取输入流对象,读取客户端发送的内容。
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int length = 0;
        length = inputStream.read(buf);
        System.out.println("服务端接收:"+ new String(buf,0,length)); 
        //获取socket输出流对象,想客户端发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("客户端你好啊!".getBytes());   
        //关闭资源
        serverSocket.close();   
    }
}

4、 需求: 客户端与服务端一问一答聊天。
① 如果使用BuffrerdReader的readline方法一定要加上\r\n才把数据写出。
② 使用字符流一定要调用flush方法数据才会写出。

//聊天的客户端
public class ChatClient {
    public static void main(String[] args) throws IOException {
        //建立tcp的客户端服务
        Socket socket = new Socket(InetAddress.getLocalHost(),9090);
        //获取socket的输出流对象。
        OutputStreamWriter socketOut =  new OutputStreamWriter(socket.getOutputStream());
        //获取socket的输入流对象
        BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //获取键盘的输入流对象,读取数据
        BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        //不断的读取键盘录入的数据,然后把数据写出
        while((line = keyReader.readLine())!=null){
            socketOut.write(line+"\r\n");
            //刷新
            socketOut.flush();
            //读取服务端回送的数据
            line = socketReader.readLine();
            System.out.println("服务端回送的数据是:"+line);
        }
        //关闭资源
        socket.close();
    }   
}
//聊天的服务端
public class ChatServer {
    public static void main(String[] args) throws IOException {
        //建立tcp的服务端
        ServerSocket serverSocket = new ServerSocket(9090);
        //接受客户端的连接,产生一个SOcket
        Socket socket = serverSocket.accept();
        //获取到Socket的输入流对象
        BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //获取到Socket输出流对象
        OutputStreamWriter socketOut =  new OutputStreamWriter(socket.getOutputStream());
        //获取键盘的输入流对象
        BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
        //读取客户端的数据
        String line = null;
        while((line = socketReader.readLine())!=null){
            System.out.println("服务端接收到的数据:"+ line);
            System.out.println("请输入回送给客户端的数据:");
            line = keyReader.readLine();
            socketOut.write(line+"\r\n");
            socketOut.flush();
        }   
        //关闭资源
        serverSocket.close();
    }
}

5、编写一个服务端可以给多个客户端发送图片(多线程)

public class ImageServer extends Thread {
    Socket socket ;
    //使用该集合是用于存储ip地址的。
    static HashSet<String> ips = new HashSet<String>();
    public  ImageServer(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //获取到socket输出流对象
            OutputStream outputStream = socket.getOutputStream();
            //获取图片的输入流对象
            FileInputStream fileInputStream = new FileInputStream("F:\\美女\\3.jpg");
            //读取图片数据,把数据写出
            byte[] buf = new byte[1024];
            int length = 0 ; 
            while((length = fileInputStream.read(buf))!=-1){        
                outputStream.write(buf,0,length);
            }
            String ip = socket.getInetAddress().getHostAddress();
            // socket.getInetAddress() 获取对方的IP地址
            if(ips.add(ip)){
                System.out.println("恭喜"+ip+"同学成功下载,当前下载的人数是:"+ ips.size());
            }
            //关闭资源
            fileInputStream.close();
            socket.close();
        }catch (IOException e) {    
        }
    }
    public static void main(String[] args) throws IOException {
        //建立tcp的服务 ,并且要监听一个端口
        ServerSocket serverSocket  = new ServerSocket(9090);
        while(true){
            //接受用户的链接。
            Socket socket = serverSocket.accept();
            new ImageServer(socket).start();        
        }
    }
}
//下载图片的客户端
public class ImageClient {
    public static void main(String[] args) throws Exception{
        //建立tcp的服务
        Socket socket = new Socket(InetAddress.getLocalHost(),9090);
        //获取socket的输入流对象
        InputStream inputStream = socket.getInputStream();
        //获取文件的输出流对象
        FileOutputStream fileOutputStream = new FileOutputStream("F:\\3.jpg");
        //边读边写
        byte[] buf = new byte[1024];
        int length = 0 ; 
        while((length = inputStream.read(buf))!=-1){
            fileOutputStream.write(buf,0,length);
        }
        //关闭资源
        fileOutputStream.close();
        socket.close(); 
    }   
}

6、实现登陆与注册功能。
客户端与服务端连接的时候,就要提示客户端请选择功能。客户端注册的时候,用户名与密码都是发送给服务端 的,服务端需要把数据保存到服务端的文件上。登陆: 登陆的时候客户端输入用户名与密码发送给服务端,服务端需要校验,返回结果给客户端。

public class LoginClinet {
    public static void main(String[] args) throws IOException {     
        Socket socket = new Socket(InetAddress.getLocalHost(),9090);
        //获取socket的输出流对象
        OutputStreamWriter  socketOut = new OutputStreamWriter(socket.getOutputStream());
        //获取到socket的输入流对象
        BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //获取到键盘的输入流对象
        BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            System.out.println("请选择功能: A(登陆)  B(注册)");
            String option = keyReader.readLine();
            if("a".equalsIgnoreCase(option)){
                getInfo(socketOut, keyReader, option);
                //读取服务器反馈的信息
                String line = socketReader.readLine();
                System.out.println(line);
            }else if("b".equalsIgnoreCase(option)){
                getInfo(socketOut, keyReader, option);
                //读取服务器反馈的信息
                String line = socketReader.readLine();
                System.out.println(line);
            }
        }   
    }
    public static void getInfo(OutputStreamWriter  socketOut,BufferedReader keyReader, String option)
            throws IOException {
        System.out.println("请输入用户名:");
        String userName = keyReader.readLine();
        System.out.println("请输入密码:");
        String password = keyReader.readLine();
        String info = option +" "+userName+" "+password+"\r\n";
        socketOut.write(info);
        socketOut.flush();
    }
}
public class LoginServer extends Thread {
    Socket socket;
    static File file = new File("F:\\users.properties");
    public LoginServer(Socket socket) {
        this.socket = socket;
    }
    static {
        try {
            if (!file.exists()) {
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
    while(true){
            try {
                // 获取socket的输入流对象
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));
                // 获取socket的输出流对象
                OutputStreamWriter socketOut = new OutputStreamWriter(
                        socket.getOutputStream());
                // 读取客户端输入的信息
                String info = bufferedReader.readLine();
                String[] datas = info.split(" ");
                // 获取到用户 的选择功能
                String option = datas[0];
                // 注册
                String userName = datas[1];
                String password = datas[2];
                if ("a".equalsIgnoreCase(option)) {
                    // 登陆
                    Properties properties = new Properties();
                    // 加载配置文件
                    properties.load(new FileReader(file));
                    if (properties.containsKey(userName)) {
                        String tempPass = properties.getProperty(userName);
                        if (password.equals(tempPass)) {
                            socketOut.write("欢迎" + userName + "登陆成功\r\n");
                        } else {
                            socketOut.write("密码错误\r\n");
                        }
                    } else {
                        socketOut.write("用户名不存在,请重新输入...\r\n");
                    }
                    socketOut.flush();
                } else if ("b".equalsIgnoreCase(option)) {
                    // 创建一个配置文件类
                    Properties properties = new Properties();
                    //加载原来的配置文件
                    properties.load(new FileReader(file));
                    if (!properties.containsKey(userName)) {
                        // 不存在该用户名
                        properties.setProperty(userName, password);
                        // 生成一个配置文件
                        properties.store(new FileWriter(file), "users");
                        socketOut.write("注册成功..\r\n");
                    } else {
                        // 存在用户名
                        socketOut.write("用户名已经被注册,请重新输入\r\n");
                    }
                    socketOut.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9090);
        while (true) {
            Socket socket = serverSocket.accept();
            new LoginServer(socket).start();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Mr_GaoYang/article/details/81010212
今日推荐