Java网络编程之UDP实现原理解析

网友投稿 255 2022-12-11

Java网络编程之UDP实现原理解析

UDP实现通信非常简单,没有服务器,每个都是客户端,每个客户端都需要一个发送端口和一个接收端口。一个客户端向另一个客户端发送消息时,需要知道对方的IP和接收端口,所用到的类为DatagramSocket。

DatagramSocket socket =new DatagramSocket(),发送端socket,若不指定端口,系统自动分配

DatagramSocket socket =new DatagramSocket("接收信息端口"),接收端socket,需要指定接收端口

​ 若想客户端之间进行全双工通信,每个客户端都要有两个线程,一个用于发送信息,一个用于接收信息。

​ 那么UDP怎么实现私聊和群聊呢?(在本机一台电脑的情况下实现)

​ 首先私聊,客户端向另一个客户端发送消息,就要知道其IP(本机都是固定的localhost)和接收端口,也需要姓名进行标识,所以,每个客户端都至少要自己的姓名和接收端口,而且端口不可重复,否则会报端口被占用的错。

​ 其次群聊,由于在本机一台电脑上进行,接收端口各不相同,所以广播就不行了,此时就希望每个客户端在启动的时候,能够把自己的姓名和接收端口给存起来,然后就可以遍历进行群聊。

​ 实现:

第一种,在每个客户端启动时,输入自己的姓名和接收端口,发送信息时,需要输入对方的接收端口号,如果输入时输入了多个端口,就是群发。那么这样每次发送信息时都要指定对方的端口。。。

第二种,客户端启动时,输入姓名和接收端口,此时就把数据存起来,发送信息时,只用指定对方姓名即可。。。可用数据库存,可用文件存,我用的是XML来存。

要创建xml文件,路径在Operation类中

UdpClient.java:

public class UdpClient {

public static void main(String[] args) {

try {

Scanner scanner = new Scanner(System.in);

User user = new User();

System.out.print("请输入用户名》》");

String userName = scanner.next();

if (Operation.userIsExist(userName)) {

//如果此用户已经注册过,直接把注册时用的接收端口分配给他

user = Operation.findUserByName(userName);

}else {

//未注册,用户自己指定端口

while(true) {

System.out.println("请输入接收端口》》");

int port = Integer.parseInt(scanner.next());

if (Operation.portIsExist(port)) {

System.err.println("该端口已被使用,请重新输入。。。。");

continue;

}else {

user.setName(userName);

user.setPort(port);

Operation.addUser(user);

break;

}

}

}

new Thread(new SendMsg(user)).start();

new Thread(new ReceiveMsg(user)).start();

} catch (Exception e) {

e.printStackTrace();

}

}

}

发送信息:

public class SendMsg implements Runnable{

private User self = null;

private DatagramSocket socket = null;

private BufferedReader reader = null;

public SendMsg(User self) {

try {

socket = new DatagramSocket();

reader = new BufferedReader(new InputStreamReader(System.in));

this.self = self;

} catch (Exception e) {

e.printStackTrace();

}

}

@Override

public void run() {

try {

while(true) {

String[] msg = reader.readLine().split("@");

if (msg.length != 2) {

System.err.println("注意格式:消息@对方名字(私聊)或all(群聊)");

continue;

}

msg[0] = self.getName()+"说:"+msg[0];

byte[] data = msg[0].getBytes();

String toPerson = msg[1];

if (("all").equals(toPerson)) {

//群聊,获取所有用户,不管对方在不在线,都发过去

List users = Operation.getUsers();

for(User user:users) {

if (self != user) {

DatagramPacket packet = new DatagramPacket(data, 0,data.length,new InetSocketAddress("localhost",user.getPort()));

socket.send(packet);

}

}

}else {

//私聊

try {

DatagramPacket packet = new DatagramPacket(data, 0,data.length,new InetSocketAddress("localhost",Operation.findUserByName(toPerson).getPort()));

socket.send(packet);

} catch (Exception e) {

System.out.println("对方不在线。。。");

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

接收消息:

public class ReceiveMsg implements Runnable{

private DatagramSocket socket = null;

public ReceiveMsg(User user) {

try {

socket = new DatagramSocket(user.getPort());

} catch (Exception e) {

e.printStackTrace();

}

}

@Override

public void run() {

try {

while(true) {

//准备接收包裹

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(receiveData);

}

} catch (Exception e) {

e.printStackTrace();

}

socket.close();

}

}

操作XML文件类:

public class Operation {

private static String FILE_PATH = "config/user.xml"; //文件目录

//在xml文件中添加一个用户信息

public static void addUser(User user)

{

InputStream in = null;

SAXReader reader = new SAXReader();YgdfQqQm

Document doc = null;

try

{

in = new FileInputStream(FILE_PATH);

doc = reader.read(in);

Element root = doc.getRootElement(); //获取xml根节点,即users节点

Element element = root.addElement("user");

element.addElement("name").addText(user.getName());

element.addElement("port").addText(String.valueOf(user.getPort()));

FileOutputStream fos = new FileOutputStream(FILE_PATH);

//格式化xml文件

OutputFormat format = OutputFormat.createPrettyPrint();

format.setEncoding("utf-8");

XMLWriter writer = new XMLWriter(fos,format);

writer.write(doc);

writer.close();

}

catch (Exception e)

{

System.out.println("error");

}

finally

{

try

{

if(in != null)

in.close();

}

catch (IOException e)

{

System.out.println("error");

}

}

}

//列出xml中所有用户信息

public static List getUsers()

{

InputStream in = null;

SAXReader reader = new SAXReader();

Document doc = null;

List users = new ArrayList<>();

try

{

in = new FileInputStream(FILE_PATH);

doc = reader.read(in);

Element root = doc.getRootElement();

List elements = root.elements();

for (Element element : elements)

{

User user = new User();

user.setName(element.elementText("name"));

user.setPhttp://ort(Integer.valueOf(element.elementText("port")));

users.add(user);

}

}

catch (Exception e1)

{

System.out.println("error");

}

finally

{

try

{

in.close();

}

catch (IOException e)

{

System.out.println("error");

}

}

return users;

}

public static User findUserByName(String name) {

InputStream in = null;

SAXReader reader = new SAXReader();

Document doc = null;

try {

in = new FileInputStream(FILE_PATH);

doc = reader.read(in);

Element root = doc.getRootElement();

List elements = root.elements();

for (Element element : elements)

{

if(name != null && name.equals(element.elementText("name"))) {

User user = new User();

user.setName(name);

user.setPort(Integer.parseInt(element.elementText("port")));

return user;

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (DocumentException e) {

e.printStackTrace();

}

return null;

}

public static boolean portIsExist(int port) {

InputStream in = null;

SAXReader reader = new SAXReader();

Document doc = null;

try {

in = new FileInputStream(FILE_PATH);

doc = reader.read(in);

Element root = doc.getRootElement();

List elements = root.elements();

for (Element element : elements)

{

if(port == Integer.parseInt(element.elementText("port")))

return true;

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (DocumentException e) {

e.printStackTrace();

}

return false;

}

//判断某个用户是否存在该xml中

public static boolean userIsExist(String name)

{

InputStream in = null;

SAXReader reader = new SAXReader();

Document doc = null;

try {

in = new FileInputStream(FILE_PATH);

doc = reader.read(in);

Element root = doc.getRootElement();

List elements = root.elements();

for (Element element : elements)

{

if(name != null && name.equals(element.elementText("name")))

return true;

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (DocumentException e) {

e.printStackTrace();

}

return false;

}

}

用户实体类:

public class User implements Serializable{

private String name;//姓名

private int port;//接收端口

public String getName() {

return name;

}

public int getPort() {

return port;

}

public void setName(String name) {

this.name = name;

}

public void setPort(int port) {

this.port = port;

}

@Override

public String toString() {

return "User [name=" + name + ", port=" + port + "]";

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何使用JJWT及JWT讲解和工具类
下一篇:Java spring单点登录系统
相关文章

 发表评论

暂时没有评论,来抢沙发吧~