首页 技术 正文
技术 2022年11月15日
0 收藏 368 点赞 4,413 浏览 12200 个字

程序说明:

以下代码,利用java的网络编程,使用UDP通信作为通信协议,描述了一个简易的多人聊天程序,此程序可以使用公网或者是局域网进行聊天,要求有一台服务器。程序一共分为2个包,第一个包:udp,放置服务器端代码,包括:Server.java,第二个包:ui,放置客户端代码,包括:Login.java,Chat.java,Sender.java,Reciever.java,Test.java,期中Chat与Login为ui界面。

没有公网服务器的同学可以选择阿里云租赁【可以选择云翼计划】【非广告】,或者使用局域网,此代码使用公网ip测试成功,没有试过局域网,感兴趣的同学可以试一试。

具体代码:

Server.java:

 package udp; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.util.LinkedList;
import java.util.List; public class Server
{ public static void main(String[] args)
{
new Thread(new Server_Run()).start();
} } class Server_Run implements Runnable
{
DatagramSocket server;
DatagramPacket packetIn = null;
DatagramPacket packetOut = null;
List<InetSocketAddress> addressList = new LinkedList<InetSocketAddress>(); public void doForThis() throws IOException
{
try
{
InetAddress local = InetAddress.getLocalHost();// 得到本地地址
System.out.println("Server local address:" + local);
server = new DatagramSocket(8823, local);// 8823负责接收 while (true)
{
byte[] buff = new byte[4096];
packetIn = new DatagramPacket(buff, 1024);
// 一旦调用这一方法, 会程序的阻塞, 直到你收到有数据报为止。
server.receive(packetIn); // 每次建立连接,获取用户地址,并存储在列表中
InetSocketAddress clientAddress = (InetSocketAddress) packetIn.getSocketAddress(); // 获取客户端地址
String ip = clientAddress.getAddress().getHostAddress();
int clientport = clientAddress.getPort();// 必须要通过端口号来找到客户端
if (!addressList.contains(clientAddress))
{
addressList.add(new InetSocketAddress(ip, clientport));
} byte[] temp = packetIn.getData();
int size = packetIn.getLength();
String content = new String(temp, 0, size, "UTF-8");
URLDecoder.decode(content, "utf-8");
if (size > 0)
{
System.out.println(content);
}
URLEncoder.encode(content, "utf-8");
for (InetSocketAddress clientisa : addressList)
{
packetOut = new DatagramPacket(content.getBytes("UTF-8"), 0, content.getBytes("UTF-8").length,
clientisa);// offset=0 偏移量
server.send(packetOut);
} }
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
} public void run()
{
try
{
doForThis();
} catch (IOException e)
{
e.printStackTrace();
}
} }

Login.java:

 package ui; import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern; import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager; class Login implements ActionListener, KeyListener
{ JFrame frame;
JLabel logo;
JLabel lbl1, lbl2;
JTextField jtf1, jtf2;
JButton jb1, jb2;
JPanel jp1, jp2, jp3, jp4;
ImageIcon img, head;
int width = 400;
int height = 650; String address;
String name;
public static void setUIFont()
{
Font f = new Font("宋体",Font.BOLD,18);
String names[]={ "Label", "CheckBox", "PopupMenu","MenuItem", "CheckBoxMenuItem",
"JRadioButtonMenuItem","ComboBox", "Button", "Tree", "ScrollPane",
"TabbedPane", "EditorPane", "TitledBorder", "Menu", "TextArea",
"OptionPane", "MenuBar", "ToolBar", "ToggleButton", "ToolTip",
"ProgressBar", "TableHeader", "Panel", "List", "ColorChooser",
"PasswordField","TextField", "Table", "Label", "Viewport",
"RadioButtonMenuItem","RadioButton", "DesktopPane", "InternalFrame"
};
for (String item : names) {
UIManager.put(item+ ".font",f);
}
} public Login() throws IOException
{
setUIFont();
img = new ImageIcon(Login.class.getResource("/img/logo.jpg"));
head = new ImageIcon(Login.class.getResource("/img/head.png"));// 此句暂时无效
img.setImage(img.getImage().getScaledInstance(width, 360, Image.SCALE_DEFAULT));
lbl1 = new JLabel("请输入服务器地址:");
lbl2 = new JLabel("请输入用户名:");
logo = new JLabel(img);// 预备图片
jb1 = new JButton("加入");
jb2 = new JButton("退出");
jb1.addActionListener(this);
jb2.addActionListener(this);
jtf1 = new JTextField(20);
jtf2 = new JTextField(20);
jp1 = new JPanel();
jp2 = new JPanel();
jp3 = new JPanel();
jp4 = new JPanel();
jp1.add(logo);
jp2.add(lbl1);
jp2.add(jtf1);
jp3.add(lbl2);
jp3.add(jtf2);
jp4.add(jb1);
jp4.add(jb2); jtf1.addKeyListener(this);// 绑定enter
jtf2.addKeyListener(this);// 绑定enter
frame = new JFrame("PLMM聊天室");
frame.setIconImage(head.getImage());
frame.setLayout(new FlowLayout(1, 20, 30));
frame.add(jp1);
frame.add(jp2);
frame.add(jp3);
frame.add(jp4);
frame.setLocationRelativeTo(null);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} // 以下代码判断ip是否可连接,未完成
// public boolean isHostConnectable(String host, int port)
// {
// Socket socket = new Socket();
// try
// {
// socket.connect(new InetSocketAddress(host, port));
// } catch (ConnectException e)
// {
// e.printStackTrace();
// return false;
// } catch (IOException e)
// {
// e.printStackTrace();
// return false;
// } finally
// {
// try
// {
// socket.close();
// } catch (IOException e)
// {
// e.printStackTrace();
// }
// }
// return true;
// } // // 以下代码判断ip是否超时
public boolean isHostReachable(String host, Integer timeOut)
{
try
{
return InetAddress.getByName(host).isReachable(timeOut);
} catch (ConnectException e)
{
e.printStackTrace();
} catch (UnknownHostException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
return false;
} public void connect()
{
// 下面判断用户名
if (jtf2.getText().length() > 8)
{ // 对用户名长度进行限制
JOptionPane.showMessageDialog(null, "用户名长度必须小于8!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (jtf2.getText().length() == 0)
{ // 为空判断
JOptionPane.showMessageDialog(null, "用户名不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} else
{
name = jtf2.getText();
}
// 下面判断ip地址
address = jtf1.getText();
Pattern pattern = Pattern.compile(
"^(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-5][0-5])$"); // IP正则表达式
boolean flag = pattern.matcher(address).matches();
if (address.length() == 0)
{ // 为空判断
JOptionPane.showMessageDialog(null, "IP地址不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (flag == false)
{ // IP正则匹配
JOptionPane.showMessageDialog(null, "IP地址不正确!", "Warning", JOptionPane.ERROR_MESSAGE);
} else if (isHostReachable(address, 1000) == false)
{// 判断是否连接超时
JOptionPane.showMessageDialog(null, "IP连接超时!", "Warning", JOptionPane.ERROR_MESSAGE);
} else
{
frame.setVisible(false); // 如何实现真正的关闭?且不退出程序(不中断下一步执行)
frame = null;
frame = new Chat(address, name);// 传入address
}
} public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jb1)
{
connect(); } else if (e.getSource() == jb2)
{
System.exit(0);
}
} public void keyTyped(KeyEvent e)
{ } public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
connect();
} } public void keyReleased(KeyEvent e)
{ } }

Chat.java:

 package ui; import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea; public class Chat extends JFrame implements ActionListener, KeyListener
{
private static final long serialVersionUID = 1L;
double initWidth = 800;
double initHeight = 600; JPanel jp1, jp2; // 定义面板
JSplitPane jsp; // 定义拆分窗格
JTextArea jta1, jta2; // 定义文本域
JScrollPane jspane1, jspane2; // 定义滚动窗格 JButton jb1, jb2; // 定义按钮 String addressSTR;
String name;
String messageOut = "";
String messageIn = ""; public Chat(String addressSTR, String name)
{ this.addressSTR = addressSTR;
this.name = name; jta1 = new JTextArea(); // 创建多行文本框
jta2 = new JTextArea();
jta1.setLineWrap(true); // 设置多行文本框自动换行
jta1.setEditable(false); // 禁止用户修改公屏信息
jta1.addKeyListener(this);
jta2.setLineWrap(true);
jta2.addKeyListener(this);
jspane1 = new JScrollPane(jta1); // 创建滚动窗格
jspane2 = new JScrollPane(jta2);
jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, jspane1, jspane2); // 创建拆分窗格 double initSep = initHeight * 2 / 3; jsp.setDividerLocation((int) initSep); // 设置拆分窗格分频器初始位置
jsp.setDividerSize(1); // 设置分频器大小
jb1 = new JButton("发送"); // 创建按钮
jb2 = new JButton("关闭");
jb1.addActionListener(this);
jb2.addActionListener(this);
jp1 = new JPanel(); // 创建面板
jp2 = new JPanel();
jp1.setLayout(new BorderLayout()); // 设置面板布局
jp2.setLayout(new FlowLayout(FlowLayout.RIGHT));
jp1.add(jsp); // 分频器
jp2.add(jb1); // 按钮
jp2.add(jb2); this.add(jp1, BorderLayout.CENTER);
this.add(jp2, BorderLayout.SOUTH); // 设置窗体实行
this.setTitle("澳门聊天室-人间天堂"); // 设置界面标题
// this.setIconImage(new ImageIcon(User_chat.class.getClassLoader().getResource("Head.png")).getImage());
this.setSize((int) initWidth, (int) initHeight); // 设置界面像素
this.setLocationRelativeTo(null); // 居中运行
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置虚拟机和界面一同关闭
this.setVisible(true); // 设置界面可视化 new Thread(new Reciever(addressSTR, messageIn, jta1)).start();
} public void sendOut()
{
messageOut = jta2.getText();
if (messageOut.hashCode() != 0) // 此处必须用hash
{
new Thread(new Sender(addressSTR, name, messageOut)).start();
jta2.setText("");
} else
{
JOptionPane.showMessageDialog(null, "发送消息不能为空!", "Warning", JOptionPane.ERROR_MESSAGE);
} } public void scrollAndSetCursor(JTextArea jta)
{
// 自动滚动
jta.setSelectionStart(jta.getText().length()); } public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jb1)
{
// 发送
sendOut(); } else if (e.getSource() == jb2)
{
System.exit(0); }
} public void keyTyped(KeyEvent e)
{ } public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_CONTROL + KeyEvent.VK_ENTER)
{
sendOut();
}
} public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
jta2.setText("");
} }
}

Sender.java:

 package ui; import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.URLEncoder;
import java.net.UnknownHostException; public class Sender implements Runnable
{
String address = "";
String name = "";
DatagramSocket socket = null;
DatagramPacket packetOut = null;
String messageOut = ""; public Sender(String address, String name, String messageOut)
{
this.address = address;
this.name = name;
this.messageOut = messageOut;
} public void doForThis() throws IOException
{ try
{
if (messageOut.length() != 0)
{
socket = new DatagramSocket(8823); // 进行一次发送
InetSocketAddress isa = new InetSocketAddress(address, 8823); String content = name + ":" + messageOut;
URLEncoder.encode(content, "utf-8"); packetOut = new DatagramPacket(content.getBytes("UTF-8"), content.getBytes("UTF-8").length, isa);
socket.send(packetOut);
messageOut = "";
socket.close();
// socket.receive(packetOut);
// String message = new String(packetOut.getData(), 0, packetOut.getLength());
// System.out.println("本机端口和IP信息:" + message);
// int clientListenPort = Integer.valueOf(message.split(":")[1]);
// System.out.println(clientListenPort);
}
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnknownHostException e)
{
e.printStackTrace();
} finally
{ } } public void run()
{
try
{
System.out.println("sender is running");
doForThis();
} catch (IOException e)
{
e.printStackTrace(); }
} }

Reciever.java:

 package ui; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.URLDecoder; import javax.swing.JTextArea; public class Reciever implements Runnable
{
String strAddress = "";
String name = "";
String messageOut = "";
String messageIn = "";
DatagramSocket socket = null;
DatagramPacket packet = null;
int clientListenPort;
JTextArea jta1; public Reciever(String strAddress, String messageIn, JTextArea jta1)
{
this.strAddress = strAddress;
this.messageIn = messageIn;
this.jta1 = jta1;
} // @SuppressWarnings("resource") 此处也不能加
public void doForThis() throws IOException
{
SocketAddress server = new InetSocketAddress(strAddress, 8823);
@SuppressWarnings("resource")
DatagramSocket ds = new DatagramSocket(); // ds必须经过一次发送和接收,为什么呢?
byte buff[] = new byte[1024];
DatagramPacket dp = new DatagramPacket(buff, 0, 0, server);
ds.send(dp);// 发送信息到服务器
ds.receive(dp);
try
{
socket = new DatagramSocket(); // 负责接收 while (true)
{
packet = new DatagramPacket(buff, 1024);// 实现接收 ds.receive(packet); byte[] temp = packet.getData();
int size = packet.getLength();
if (size > 0)
{
String content = new String(temp, 0, size, "UTF-8");
// System.out.println(content);
URLDecoder.decode(content, "utf-8");
messageIn = "\n" + content;
jta1.append(messageIn);
// 自动滚动
scrollAndSetCursor(jta1);
}
}
} catch (SocketException e)
{
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
} public void scrollAndSetCursor(JTextArea jta)
{
// 自动滚动
jta.setSelectionStart(jta.getText().length()); } public void run()
{
try
{
System.out.println("receiver is running");
doForThis();
} catch (IOException e)
{
e.printStackTrace();
}
}
}

Test.java:

 package ui; import java.io.IOException; public class Test
{
public static void main(String[] args) throws IOException
{
new Login();
}
}

测试结果:

注意我Login代码里的img,没有在对应路径放置图片的话是无法显示的,我放在bin目录下自己创建的img文件夹里。

登录界面,【忽略窗口名】:

Java入门网络编程-使用UDP通信

登录进去后,测试聊天【忽略窗口名】:

Java入门网络编程-使用UDP通信

转载请说明原文地址,谢谢!

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,964
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,486
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,331
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,114
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,747
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,781