Python 每日一记214>>>UDP协议下模拟聊天小程序

这里客户端和服务器都分别使用了两个线程:
一个线程用于接收数据,一个线程用于发送数据,这样就可以实现别人一直发都行,你一直收也行。
如果只是一个线程用于收发数据,就只能你发一天,他收一条,然后他发一条,你收一条,这样不是很现实。

话不多说直接上程序,程序内有部分代码解释:

服务器端

/*
* TCP是面向连接的,在建立套接字的时候客户端套接字就要指定服务器的IP和端口号,
* 服务器只用指定服务器的端口号就行了。
*
* UDP是面向非连接的,本质上没有客户端和服务器之分,建立套接字时不需要指定IP地址,
* 但是有一个必须要指定端口号,他们之间靠数据报包产生联系,发送方需要将数据转化为字节数组,
* 注意只能是字节数组,然后打包为数据包,发送出去,发送包的时候指定目的IP和端口号,
* 这时接收方在建立套接字的时候就必须指定端口号了,这个端口号就是发送方在发送包时写的端口号,
* 如果双发都要发送数据,那么另外一方就都需要指定端口号。
* 接收方在接收数据的时候,也是通过包来接受的,先准备一个字节数组,作为包的参数,创建包,
* 然后接收数据,在解析数据
*
* 这里客户端和服务器都分别使用了两个线程,
* 一个线程用于接收数据,一个线程用于发送数据,这样就可以实现别人一直发都行,你一直收也行。
* 如果只是一个线程用于收发数据,就只能你发一天,他收一条,然后他发一条,你收一条,这样不是很现实。
* */

package mypackage;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class UDPServer {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器开始运行");
//        创建套接字,指定服务器端口,这个端口和客户端发送包时的端口一致
        DatagramSocket socket=new DatagramSocket(8080);
//        发数据线程
        Thread t1 =new Thread(()->{
            while (true){
                //        收数据准备一个字节数组
                byte[] buf2=new byte[1014];
//                创建包
                DatagramPacket packet1=new DatagramPacket(buf2,buf2.length);
                try {
//                    接收数据包
                    socket.receive(packet1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
//                返回接收包内数据的长度
                int len=packet1.getLength();
//                转化为字符串,也可以String str1=new String(buf2,0,len);
                String str1=new String(packet1.getData(),0,len);
//                打印收到的内容
                System.out.printf("从客户端接收的数据:【%s】\n",str1);
            }
        });

//收数据线程
        Thread t2 =new Thread(()->{
            while (true){
//        发数据
//                键盘输入流
                BufferedReader KeyboardIn=new BufferedReader(new InputStreamReader(System.in));
                String str= null;
                try {
//                    读取键盘输入的内容
                    str = new String(KeyboardIn.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
//                将键盘输入的内容更改为字节数组
                byte[] buf=str.getBytes();
                DatagramPacket packet= null;
                try {
                    //发送数据时,这个包一定要指定发送的地址,端口号与客户段的端口号一样
                    packet = new DatagramPacket(buf,buf.length, InetAddress.getByName("127.0.0.1"),7777);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                try {
//                    发送包
                    socket.send(packet);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
//        启动线程
        t1.start();
        t2.start();
    }
}

客户端

/*
 * TCP是面向连接的,在建立套接字的时候客户端套接字就要指定服务器的IP和端口号,
 * 服务器只用指定服务器的端口号就行了。
 *
 * UDP是面向非连接的,本质上没有客户端和服务器之分,建立套接字时不需要指定IP地址,
 * 但是有一个必须要指定端口号,他们之间靠数据报包产生联系,发送方需要将数据转化为字节数组,
 * 注意只能是字节数组,然后打包为数据包,发送出去,发送包的时候指定目的IP和端口号,
 * 这时接收方在建立套接字的时候就必须指定端口号了,这个端口号就是发送方在发送包时写的端口号,
 * 如果双发都要发送数据,那么另外一方就都需要指定端口号。
 * 接收方在接收数据的时候,也是通过包来接受的,先准备一个字节数组,作为包的参数,创建包,
 * 然后接收数据,在解析数据
 *
 * 这里客户端和服务器都分别使用了两个线程,
 * 一个线程用于接收数据,一个线程用于发送数据,这样就可以实现别人一直发都行,你一直收也行。
 * 如果只是一个线程用于收发数据,就只能你发一天,他收一条,然后他发一条,你收一条,这样不是很现实。
 * */

//客户端程序和服务器程序基本一样,只是加了一点退出的判断指令
package mypackage;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class UDPClient {
    public static void main(String[] args) throws IOException {
        System.out.println("客户端开始运行");
//        创建套接字,指定客户端端口,这个端口和服务器发送包时的端口一致
        DatagramSocket socket=new DatagramSocket(7777);
//        收数据线程
        Thread t1 =new Thread(()->{
            while (true){
                //        收数据
                byte[] buf2=new byte[1014];
                DatagramPacket packet1=new DatagramPacket(buf2,buf2.length);
                try {
                    socket.receive(packet1);
                } catch (IOException e) {
//                    这里选择break的原因是,下面发数据的线程有设定,如果输入bye,就关闭socket
//                    关闭的话就会导致这个线程的异常,处理这个异常直接选择退出这个循环,正好可以结束程序
                    break;
                }
                int len=packet1.getLength();
                String str1=new String(packet1.getData(),0,len);
                System.out.printf("从服务器接收的数据:【%s】\n",str1);
            }
        });

        Thread t2 =new Thread(()->{
            while (true){
//发数据线程
//        发数据
                BufferedReader KeyboardIn=new BufferedReader(new InputStreamReader(System.in));
                String str= null;
                try {
                    str = new String(KeyboardIn.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                byte[] buf=str.getBytes();
                DatagramPacket packet= null;
                try {
//                    发送数据时,这个包一定要指定发送的地址
                    packet = new DatagramPacket(buf,buf.length, InetAddress.getByName("127.0.0.1"),8080);
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                try {
                    socket.send(packet);
                } catch (IOException e) {
                    e.printStackTrace();
                }
//                先把数据发出去,再判断,如果数据为bye,那么主动关闭套接字并退出循环
//                服务器那边一直等待不关闭
                if(str.equals("bye")){
                    System.out.println("客户端停止");
                    socket.close();
                    break;
                }
            }
        });
//        启动线程
        t1.start();
        t2.start();
    }
}

结果测试

在这里插入图片描述
在这里插入图片描述

发布了235 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_44663675/article/details/104450667