UDP网络编程+IO+多线程 ---->聊天室

网络编程

​ UDP网络编程+IO+多线程 ---->聊天室

UDP是一个非连接的协议,传输数据之前源端和终端不建立连接, 当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常, 其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包, 如果数据包是否到达的消息及时反馈回来,那么网络就是通的。

思路:UDP实现单向数据发送,即一个发送方一个接收方。聊天需要双向发送消息,我们可以写两个类分别实现发送信息和接收消息且让他们实现 Runnable接口 ,这样聊天时同时运行发送消息和接收消息的线程。

Socket 套接字

发送端类

package SocketProgramming;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

//UDP消息发送不需要链接服务器

//发送端
public class TalkSend implements Runnable{
    
    

    //建立一个Socket
    DatagramSocket socket = null;
    //IO流
    BufferedReader reader = null;
    //发出端口和接收目标的接收端口
    private int fromPort;
    private int toPort;
    //接收目标IP
    private String toIP;

    public TalkSend(int fromPort, String toIP, int toPort) {
    
    
        this.fromPort = fromPort;
        this.toIP = toIP;
        this.toPort = toPort;

        try {
    
    
            socket = new DatagramSocket(fromPort);
            //控制台读取文字 System.in
            reader = new BufferedReader(new InputStreamReader(System.in));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
    
    
        while (true){
    
    
            try {
    
    
                //读入数据
                String data = reader.readLine();
                //转为字节流
                byte[] datas = data.getBytes();
                //数据包:数据,数据长度,发送给谁(IP加端口)
                DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
                        new InetSocketAddress(this.toIP,this.toPort));
                //发送包
                socket.send(packet);
                //trim()去空格
                if (data.trim().equals("bye")){
    
    
                    break;
                }
            }catch (Exception e){
    
    
                e.printStackTrace();
            }
        }
        //程序结束记得先断开连接释放系统资源
        socket.close();
        try {
    
    
            reader.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

接收端类

package SocketProgramming;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

//接收端
public class TalkReceive implements Runnable{
    
    
    //建立一个Socket
    DatagramSocket socket = null;
    //接收者的端口
    private int port;
    //标记发送者的名字
    private String msgFrom;

    public TalkReceive(int port,String msgFrom) {
    
    
        this.port = port;
        this.msgFrom = msgFrom;
        try {
    
    
            socket = new DatagramSocket(port);
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
    
    
        while (true){
    
    
            try {
    
    
                //准备接收数据包
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container, 0 ,container.length);
                socket.receive(packet);//阻塞式接收包裹
                //读取数据
                byte[] data = packet.getData();
                String receiveData = new String(data, 0 ,data.length);

                System.out.println(msgFrom + ":"+receiveData);
                if (receiveData.trim().equals("bye")){
    
    
                    break;
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        //断开连接
        socket.close();
    }
}

两个测试类模拟两个人聊天

package SocketProgramming;

//学生和老师通信,两者都是接收方和发送方,调用两个线程接收和发送
public class TestTalkStudent {
    
    
    public static void main(String[] args) {
    
    
        //开启两个线程
        new Thread(new TalkReceive(8888,"老师")).start();
        new Thread(new TalkSend(7777,"localhost",9999)).start();
    }
}
package SocketProgramming;

public class TestTalkTeacher {
    
    
    public static void main(String[] args) {
    
    
        //开启两个线程
        new Thread(new TalkReceive(9999,"学生")).start();
        new Thread(new TalkSend(5555,"localhost",8888)).start();
    }
}

运行结果

其实和qq差不多,两个人同时上线聊天,一个人下线了还可以收到离线消息,两个人同时bye程序才结束

在这里插入图片描述

为什么close()

当我们new一个java流对象之后,不仅在计算机内存中创建了一个相应类的实例对象。而且,还占用了相应的系统资源,比如:文件句柄、端口、数据库连接等。在内存中的实例对象,当没有引用指向的时候,java垃圾收集器会按照相应的策略自动回收,但是却无法对系统资源进行释放。所以,我们需要主动调用close()方法释放java流对象。在java7之后,可以使用try-with-resources语句来释放java流对象,从而避免了try-catch-finally语句的繁琐,尤其是在finally子句中,close()方法也会抛出异常。

IO流需要强化学习!

猜你喜欢

转载自blog.csdn.net/weixin_44529429/article/details/113208126