您的位置:首页 > 编程语言 > Java开发

JAVA UDP聊天室

2015-08-21 19:37 441 查看
本文为使用UDP 进行数据传输的一个聊天室应用,使用JAVA语言开发的聊天室在目前的实际中应用很少,写这个例子的原因的进一步理解CS模式编程,掌握这种思想。

本例子分为客户端和服务器两个部分,客户端输入想要发送给的对象(IP地址)已经要发送的数据,发到服务器中,服务器对发送来的数据进行解析后转发到相应的客户端,客户端与客户端之间不进行直接的通讯,而是由服务器转发,本例子中的服务器转发部分可以再优化(如果不优化,在用户量大的时候转发效率非常低,这个在实际运用时再实际修改),客户端实现的是通过服务器向指定的客户端发送消息(实际运用中可以使用网段发送,即是向指定网段的所有客户端发消息),服务器则可以向所有的在线客户端推送消息。在例子中的一个主要思想是客户端与客户端的通讯须经过服务器端,相当于要在服务器过滤之后才进行发送。在实际的应用中客户端不能知道另一个客户端的IP地址,但是每个客户端的知道服务器的IP,我们可以用一些唯一标识(比如账号或者用户名)来标识我们的每个客户端,这样每个客户端只要知道对方的账号就可以进行通信了。

好了,不说那么多了,直接上代码,

虽然些得渣渣的,但也是自己一笔一字码出来的,望各位大神指点指点。

服务器端的代码

package com.gxuwz.fulunyong;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* @author:fulunyong
* @email:fulunyong@qq.com
* @datetime:2015年8月21日下午7:55:00
* @version 1.0
* @serial 服务器
*/
public class ChatServer extends JFrame implements ActionListener{

private static final long serialVersionUID = 4717084330471059797L;

private Integer port=2999;//系统端口

private JTextArea info;//客户端发来的消息
private JTextField msg;//推送的消息
private JButton send;//推送按钮

private List<User> users;//系统列表

private DatagramSocket socket;//传输介质

public ChatServer(){

setTitle("千锋聊天室-服务器");
setSize(400, 600);//设置窗体的大小
setLocationRelativeTo(null);//居中出现
setDefaultCloseOperation(EXIT_ON_CLOSE);//点击关闭时推出程序
//组件初始化
info=new JTextArea();
info.setEditable(false);
msg=new JTextField();
send=new JButton("推送");

send.addActionListener(this);//给按钮添加监听器

this.add(info, BorderLayout.CENTER);//把消息显示框添加到窗体的居中位置

JPanel jPanel=new JPanel(new BorderLayout());//新建一个使用盒式布局的面板
jPanel.add(msg, BorderLayout.CENTER);//把消息输入框添加到面板居中位置
jPanel.add(send, BorderLayout.EAST);//把推送按钮添加到面板的东方向

this.add(jPanel, BorderLayout.SOUTH);//把面板添加到窗体的南方向。
//初始化数据报套接字
try {
socket=new DatagramSocket(port);
} catch (SocketException e){
e.printStackTrace();
return;//如果出现异常,程序退出,窗体不应该再显示。
}

users=new ArrayList<User>();//
info.append("服务器启动成功,等待客户端连接。。。\n");//执行到这里证明已经成功启动服务器。
setVisible(true);//显示窗体

byte[] bt=new byte[1024*64];

//循环读取并转发客户端的连接及发送的数据
while(true){
DatagramPacket packet=new DatagramPacket(bt, bt.length);
try {
socket.receive(packet);
} catch (IOException e1){
e1.printStackTrace();
}
if (null!=packet){

User tempuser=new User(packet.getAddress().toString().substring(1), packet.getPort());

if (!users.contains(tempuser)){//
users.add(tempuser);
}
String temp=new String(packet.getData(), 0, packet.getLength());
String targetIp=temp.substring(0, temp.indexOf(":"));
String str=temp.substring(temp.indexOf(":")+1);

info.append(packet.getAddress().toString().substring(1)+" 对 "+targetIp+" 说:\n");

info.append(str+"\n");

for(int i = 0; i <users.size(); i++){
User user=users.get(i);
if(targetIp.equals(user.getUserIp())){//查找消息接收对象
byte[] bs=(packet.getAddress().toString().substring(1)+temp.substring(temp.indexOf(":"))).getBytes();
try {
DatagramPacket datagramPacket=new DatagramPacket(bs, bs.length, InetAddress.getByName(user.getUserIp()), user.getUserPort());
socket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
}

}
}
}
}
}

@Override
public  void  actionPerformed(ActionEvent e){
String command=e.getActionCommand();
//推送按钮事件,服务器主动给所有用户发送消息。
if("推送".equals(command)){
for(int i = 0; i <users.size(); i++){
User user=users.get(i);
String str="服务器:"+msg.getText();
byte[] bs=str.getBytes();

try {
DatagramPacket packet=new DatagramPacket(bs, bs.length, InetAddress.getByName(user.getUserIp()), user.getUserPort());
socket.send(packet);
} catch (Exception e1){
e1.printStackTrace();
}
}
}
}

public static void main(String[] args){
new ChatServer();
}

}


客户端的代码:

package com.gxuwz.fulunyong;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* @author:fulunyong
* @email:fulunyong@qq.com
* @datetime:2015年8月21日下午7:56:25
* @version 1.0
* @serial 客户端
*/
public class ChatClient extends JFrame {

private static final long serialVersionUID = -4460571879641744285L;

private JTextField toIp;//所要发送消息的对象
private JTextArea info;//消息显示框

private JTextField msg;//要发送的消息
private JButton send;//发送按钮

private DatagramSocket socket;//数据报套接字

private Integer port=6688;//客户端的端口
private Integer serverPort=2999;//服务器的端口,根据服务器实际端口修改
private String serverIp="10.16.151.90";//服务器IP 根据具体IP修改

public ChatClient(){
setTitle("千锋聊天室-客户端");//设置标题
setSize(400, 600);//设置窗口大小
setLocationRelativeTo(null);//居中出现
setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭时推出
//组件初始化
toIp=new JTextField("127.0.0.1");//默认发送的IP,默认是本机,可以在客户端修改
info=new JTextArea();
info.setEditable(false);//禁用编辑
msg=new JTextField();
send=new JButton("发送");
//给发送按钮添加事件
send.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){

String str=toIp.getText()+":"+msg.getText();
byte[] buf=str.getBytes();

try {
//拼装数据报
DatagramPacket packet=new DatagramPacket(buf, buf.length, InetAddress.getByName(serverIp), serverPort);
socket.send(packet);//发送数据报
} catch (Exception e1) {
e1.printStackTrace();
}
info.append("我说:"+msg.getText()+"\n");
msg.setText("");//清空消息输入框
msg.requestFocus();//获取鼠标焦点
}
});

this.add(toIp,BorderLayout.NORTH);//添加IP输入框到窗体的北方向。
this.add(info,BorderLayout.CENTER);//添加消息显示框到居中位置

JPanel panel=new JPanel(new BorderLayout());//新建使用盒式布局的面板
panel.add(msg, BorderLayout.CENTER);//把消息输入框添加到面板的居中位置
panel.add(send, BorderLayout.EAST);//把发送按钮添加到面板的东方向

this.add(panel, BorderLayout.SOUTH);//把面板添加到窗体的南方向

//启动数据报套接字
try {
socket=new DatagramSocket(port);
} catch (SocketException e1){
e1.printStackTrace();
return;//如果出错,程序退出。
}

setVisible(true);//显示窗体

byte[] bs=new byte[1024*64];//新建字节数组暂存数据
DatagramPacket packet=new DatagramPacket(bs, bs.length);//新建一个数据报对象

//循环读取服务器发来的消息。
while(true){
try {
socket.receive(packet);//读取消息
if(null!=packet){//不为空就显示的消息显示框
String str=new String(packet.getData(), 0, packet.getLength());
info.append(str+"\n");
}
} catch (IOException e1) {
e1.printStackTrace();
}

}

}

public static void main(String[] args){
new ChatClient();
}
}


用户类

package com.gxuwz.fulunyong;

import java.io.Serializable;
/**
* @author:fulunyong
* @email:fulunyong@qq.com
* @datetime:2015年8月21日下午8:00:29
* @version 1.0
* @serial 用户
*/
public class User implements Serializable{

private static final long serialVersionUID =-2059184085514940866L;

private String userIp;
private Integer userPort;

public User(){
}

public User(String userIp, Integer userPort) {
this.userIp = userIp;
this.userPort = userPort;
}

public String getUserIp() {
return userIp;
}
public void setUserIp(String userIp) {
this.userIp = userIp;
}
public Integer getUserPort() {
return userPort;
}
public void setUserPort(Integer userPort) {
this.userPort = userPort;
}

@Override
public String toString() {
return "User [userIp=" + userIp + ", userPort=" + userPort + "]";
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((userIp == null) ? 0 : userIp.hashCode());
result = prime * result + ((userPort == null) ? 0 : userPort.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (userIp == null) {
if (other.userIp != null)
return false;
} else if (!userIp.equals(other.userIp))
return false;
if (userPort == null) {
if (other.userPort != null)
return false;
} else if (!userPort.equals(other.userPort))
return false;
return true;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: