若使用网络编程UDP实现聊天功能,我们首先要创建两个线程
线程1:发送消息的线程
线程2:接受消息的线程
除此之外,我们还需要两个用户来进行互相沟通(互相传递信息)
用户1:发送和接受信息
用户2: 发送和接受信息
用户1向用户2发送信息:
从用户1端口--->根据IP+对方的端口号 定位到具体的人--->用户2接受到消息
用户2向用户1发送信息:
从用户2端口--->根据IP+对方的端口号 定位到具体的人--->用户1接受到消息
一、发送消息的线程
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
//用这个模仿发送消息
public class ChatSend implements Runnable{
DatagramSocket socket = null;
BufferedReader reader = null;
// 我们只有知道了对方的 端口和 ip才可以访问到具体的那个人
private String toIP; //对方的端口
private int toPort; //对方的ip
private int fromPort; //自己的端口 也就是说我们从这个端口发出的信息
public ChatSend(String toIP, int toPort, int fromPort) {
this.toIP = toIP;
this.toPort = toPort;
this.fromPort = fromPort;
try {
// 1.建立一个Socket 对象,我们要使用这个对象的sent方法发送信息
socket = new DatagramSocket(this.fromPort); //this.fromPort 是发送消息的端口号
// 这个流备用,目的就是 从 控制台读取我们想要发送的信息(读取聊天内容)
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try{
while (true){
// 2.读取控制台的信息 (返回一个字符串对象)
String msg = reader.readLine();
// 3.建立一个包
// InetAddress不能new出来,没有构造器,只能用静态方法返回回来(因为这些静态方法的返回对象就是InetAddress类型的)
InetAddress localhost = InetAddress.getByName(this.toIP);
// msg.getBytes():传递消息的字节数组 0:起始位置 msg.getBytes().length:字节数组的长度(所打包的长度)
// localhost、port :要发送给谁,具体的IP,具体的地址
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,this.toPort);
// 4.发送包(发送消息)
socket.send(packet);
// 5.根据接发送的信息,判断是否需要断开连接
if("bye".equals(msg)){
// 本地推出
System.out.println("聊天结束!!!!!");
break;
}
}
// 关闭
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
二、接受消息的线程
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
// 用这个 模仿接收消息
public class ChatReceive implements Runnable {
DatagramSocket socket = null;
private int port; //自己的端口号 也就是说我们在这个端口收集到的信息
private String receivedBy; // 这个信息从哪里来
public ChatReceive(int port,String receivedBy) {
this.port = port;
this.receivedBy = receivedBy;
try {
// 1.建立一个Socket 对象,我们要使用这个对象的receive方法接收信息
socket = new DatagramSocket(this.port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while(true){
// 2. 准备接受包裹
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length);
// 3.接收包
socket.receive(packet);//阻塞式接收包裹
// 4.转义包的信息并在控制台中输出
byte[] msgBytes = packet.getData();
// packet.getData()方法获取的是 byte数组形式的数值,我们需要把byte数组转化成字符串的形式让别人阅读
// 这里的参数的意思:将字节数组msgBytes从下标为0的开始,一直到下标packet.getLength()的字节结束,将其转化为字符串
String msg = new String(msgBytes,0, packet.getLength());
System.out.println("received by "+receivedBy+":"+msg);
// 5.根据接收到的信息,判断是否需要断开连接 bye 是断开连接
if("bye".equals(msg)){
System.out.println("聊天结束!!!!!!");
break;
}
}
socket.close(); //断开断开
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、交流对象1
public class Teacher {
public static void main(String[] args) {
// 开启两个线程
// 1.发送消息的线程
// 第一个参数是我们要把信息发送到哪个IP上 第二个参数:我们要把信息发送到哪个端口上 第三个参数:我们自己的端口是什么
// 从我们的5555端口发送到localhost:8888端口,(因为另一个人用8888接口接受消息)
Thread t1 = new Thread(new ChatSend("localhost",8888,5555));
// 2.接收消息的线程
// 第一个参数是端口号,第二个参数是 消息的来源是谁
// 我们用9999端口接受消息
Thread t2 = new Thread(new ChatReceive(9999,"学生"));
// 3.启动线程
t1.start();
t2.start();
}
}
四、交流对象2
public class Student {
public static void main(String[] args) {
// 开启两个线程
// 1.发送消息的线程
// 第一个参数是我们要把信息发送到哪个IP上 第二个参数:我们要把信息发送到哪个端口上 第三个参数:我们自己的端口是什么
// 从 我们的7777端口发送到localhost:9999端口 (因为另一个人用9999端口接收消息)
Thread t1 = new Thread(new ChatSend("localhost",9999,7777));
// 2.接收消息的线程
// 第一个参数是端口号,第二个参数是 消息的来源是谁
// 我们用8888端口接受消息
Thread t2 = new Thread(new ChatReceive(8888,"老师"));
// 3.启动线程
t1.start();
t2.start();
}
}