程序说明:

以下代码,利用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通信的更多相关文章

  1. java:网络编程(UDP (DatagramSocket和DatagramPacket)正则表达式)

    java:网络编程(UDP (DatagramSocket和DatagramPacket)正则表达式) * TCP* 特点:面向连接,点对点的通信,效率较低,但安全可靠* UDP:用户数据报协议,类似 ...

  2. 网络编程 单纯UDP通信

    网络编程 单纯UDP通信 1,UDP发送端 2,UDP接收端 UDP发送端: #include <stdio.h> #include <unistd.h> #include & ...

  3. [javaSE] 网络编程(UDP通信)

    UDP发送端 获取DatagramSocket对象,new出来 获取DatagramPacket对象,new出来,构造参数:byte[]数组,int长度,InetAddress对象,int端口 调用D ...

  4. java基础-网络编程(Socket)技术选型入门之NIO技术

    java基础-网络编程(Socket)技术选型入门之NIO技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传统的网络编程 1>.编写socket通信的MyServer ...

  5. JAVA的网络编程

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

  6. 【转】JAVA之网络编程

    转自:火之光 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者 ...

  7. JAVA的网络编程【转】

    JAVA的网络编程[转] Posted on 2009-12-03 18:04 火之光 阅读(93441) 评论(20) 编辑 收藏 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能, ...

  8. 二十三、Java基础--------网络编程

    Java中另一个重要技术就是网络编程了,为了更好的学习web方向的知识,有必要对java之网络编程好好学习,本文将围绕网络编程技术进行分析. 常见的网络协议:UDP.TCP UDP 1. 将数据源和目 ...

  9. Java面向对象 网络编程 上

     Java面向对象 网络编程 上 知识概要:                     (1)网络模型 (2)网络通讯要素 (3)UDP TCP 概念 (4)Socket (5)UDP TCP 传输 ...

随机推荐

  1. 封装QtCore(在非Qt项目里使用QString,QJson,QFileInfo,QFile等类)

    单独封装QtCore 一直以来使用QT的特性使用惯了,很多东西QT都封装得很好.如果突然有一天,不使用QT开发了,是不是不习惯. 比如我们经常使用QString很多方法,string,wstring之 ...

  2. 基于JUnit和Ant测试程序正在运行使用Kieker(AspectJ)监测方法

    这篇日志的目的从标题里能够看出来.这也是我们实验须要,必须总结一下,方便其它师弟师妹在这个基础上做实验. 我已经介绍了非常多基于Kieker的监控方法,这里以Prefuse这个开源可视化Java框架为 ...

  3. uwp - 解决使用EntityFramework时报错“unable to load dll 'sqlite3':the specified module could not be found”

    在使用uwp的ef过程中碰到一万个问题快折腾死我了,好在最后终于解决掉所有问题,但愿如此,因为在这之前先后发生不同的报错,不知道后面还会碰到新的问题不. 其中一个问题是这样的,生成能正常生成,但是启动 ...

  4. Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1)

    原文:Win7 64位系统,使用(IME)模式VS2010 编写 和 安装 输入法 教程(1) 首先感谢:http://blog.csdn.net/shuilan0066/article/detail ...

  5. WPF - 善用路由事件

    原文:WPF - 善用路由事件 在原来的公司中,编写自定义控件是常常遇到的任务.但这些控件常常拥有一个不怎么好的特点:无论是内部还是外部都没有使用路由事件.那我们应该怎样宰自定义控件开发中使用路由事件 ...

  6. [转]完美解决)Tomcat启动提示At least one JAR was scanned for TLDs yet contained no TLDs

    一.文章前言    本文是亲测有效解决At least one JAR was scanned for TLDs yet contained no TLDs问题,绝对不是为了积分随便粘贴复制然后压根都 ...

  7. 模拟请求(模拟header gzip解压 泛型)

    WebClient HeaderData是自定义类对象,存储header信息 private static T GetDataCommonMethod<T>(string url, str ...

  8. ubuntu进不去桌面

    今天折腾ubunu的时候,总是进不去桌面,开机直接进入啦终端模式.在google帮助终于解决. sudo apt install --reinstall gnome-shell ubuntu-desk ...

  9. iPhone开发笔记(20)EGOImageView的使用方法及注意事项

    EGOImageView是一种实现网络图片的异步加载和缓存的第三方类库,具有相同功能的第三方类库还有SDWebImage.但是相比两个类库的安装和使用来说,EGOImageView更简单一些,下面就介 ...

  10. 理解 node.js 的事件循环

    node.js 的第一个基本观点是,I/O 操作是昂贵的: 目前的编程技术最大的浪费来自等待 I/O 操作的完成.有几种方法可以解决这些对性能的影响(来自Sam Rushing): 同步:依次处理单个 ...