这几天偶然想研究下P2P通信的原理,于是就用Java写了一个,测试可以通过,但是在不同的运营商之间却有点问题,比如联通跟电信之间可能出现不通现象,不知是不是被卡杀了。
客户端:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Client extends Thread implements ActionListener{
//是否停止
public static int STOP=0;
//在线用户列表
public static Map<String,SocketAddress> userMap=new HashMap();
private DatagramSocket client;
private JFrame frame;
//聊天信息
private JTextArea info;
//在线用户
private JTextArea onlineUser;
private JTextField msgText;
private JButton sendButton;
public Client(DatagramSocket client)throws Exception
{
this.client=client;
this.frame=new JFrame("P2P聊天");
frame.setSize(800, 400);
sendButton=new JButton("发送");
JScrollBar scroll=new JScrollBar();
this.info=new JTextArea(10,30);
//激活自动换行功能
info.setLineWrap(true);
info.setWrapStyleWord(true);
info.setEditable(false);
scroll.add(info);
onlineUser=new JTextArea(10,30);
onlineUser.setLineWrap(true);
onlineUser.setWrapStyleWord(true);
onlineUser.setEditable(false);
JPanel infopanel=new JPanel();
infopanel.add(info,BorderLayout.WEST);
JPanel infopanel1=new JPanel();
JLabel label=new JLabel("在线用户");
infopanel1.add(label, BorderLayout.NORTH);
infopanel1.add(onlineUser, BorderLayout.SOUTH);
infopanel.add(infopanel1,BorderLayout.EAST);
JPanel panel=new JPanel();
msgText=new JTextField(30);
panel.add(msgText);
panel.add(sendButton);
frame.add(infopanel,BorderLayout.NORTH);
frame.add(panel,BorderLayout.SOUTH);
frame.setVisible(true);
sendButton.addActionListener(this);
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
/**
* 给其他在线用户发送心跳 保持session有效
*/
private void sendSkip()
{
new Thread(){
public void run()
{
try
{
String msg="skip";
while(true)
{
if(STOP==1)
break;
if(userMap.size()>0)
{
for (Entry<String, SocketAddress> entry : userMap.entrySet()) {
DatagramPacket data=new DatagramPacket(msg.getBytes(),msg.getBytes().length,entry.getValue());
client.send(data);
}
}
//每10s发送一次心跳
Thread.sleep(10*1000);
}
}catch(Exception e){}
}
}.start();
}
//主要任务是接收数据
//可以是其他用户发来的信息,也可以是服务器发来的在线用户数据
public void run()
{
try
{
String msg;
DatagramPacket data;
//执行心跳
sendSkip();
while(true)
{
if(STOP==1)
break;
byte[] buf=new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
client.receive(packet);
msg=new String(packet.getData(),0,packet.getLength());
if(msg.length()>0)
{
if(msg.indexOf("server:")>-1)
{
//服务器数据 格式server:ID#IP:PORT,。。
String userdata=msg.substring(msg.indexOf(":")+1,msg.length());
String[] user=userdata.split(",");
for(String u:user)
{
if(u!=null&&u.length()>0)
{
String[] udata=u.split("#");
String ip=udata[1].split(":")[0];
int port=Integer.parseInt(udata[1].split(":")[1]);
ip=ip.substring(1,ip.length());
SocketAddress adds=new InetSocketAddress(ip,port);
userMap.put(udata[0], adds);
//给对方打洞 发送空白报文
data=new DatagramPacket(new byte[0],0,adds);
client.send(data);
}
}
//更新在线用户列表
this.onlineUser.setText("");
for (Map.Entry<String, SocketAddress> entry : userMap.entrySet()) {
this.onlineUser.append("用户"+entry.getKey()+"("+entry.getValue()+")\n");
}
}
else if(msg.indexOf("skip")>-1);
else
{
//普通消息
this.info.append(packet.getAddress().toString()+packet.getPort()+" 说:"+msg);
this.info.append("\n");
}
}
}
}
catch(Exception e){}
}
public static void main(String args[])throws Exception
{
String serverIP="122.225.99.40";///122.225.99.40
int port=6636;
//构造一个目标地址
SocketAddress target = new InetSocketAddress(serverIP, port);
DatagramSocket client = new DatagramSocket();
String msg="向服务器报告!";
byte[] buf=msg.getBytes();
//向服务器发送上线数据
DatagramPacket packet=new DatagramPacket(buf,buf.length,target);
client.send(packet);
new Client(client).start();
}
//按钮事件
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==this.sendButton)
{
try{
String msg=this.msgText.getText();
if(msg.length()>0)
{
this.info.append("我说:"+msg);
this.info.append("\n");
for (Map.Entry<String, SocketAddress> entry : userMap.entrySet()) {
DatagramPacket data=new DatagramPacket(msg.getBytes(),msg.getBytes().length,entry.getValue());
client.send(data);
}
this.msgText.setText("");
}
}
catch(Exception ee){}
}
}
}
服务器端:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 服务端
* @author ggxin
*
*/
public class Server extends Thread{
//存储所有的用户IP与端口
public static List<Map> userList=new ArrayList<Map>();
//在线用户IP
public static Map users=new HashMap();
public static int index=1;
private DatagramSocket server;
public Server(DatagramSocket server)
{
this.server=server;
}
//线程负责给在线用户发送当前所有在线用户的信息
public void run()
{
try
{
DatagramPacket sendPacket;
StringBuffer msg;
while(true)
{
for(Map user:Server.userList)
{
//服务器数据,标记server:
msg=new StringBuffer("server:");
for(Map map:Server.userList)
{
if(!map.get("id").toString().equals(user.get("id").toString()))
{
msg.append(map.get("id")+"#"+map.get("ip")+":"+map.get("port"));
msg.append(",");
}
}
if(!msg.toString().equals("server:"))
{
byte[] data=msg.toString().getBytes();
//构造发送报文
sendPacket = new DatagramPacket(data, data.length, (InetAddress)user.get("ip"), (Integer)user.get("port"));
server.send(sendPacket);
}
}
Thread.sleep(2000);
}
}catch(Exception e){}
}
public static void main(String args[])throws Exception
{
int port=6636;
//创建一个UDPsocket
DatagramSocket server = new DatagramSocket(port);
byte[] buf = new byte[1024];
//接收数据的udp包
DatagramPacket packet = new DatagramPacket(buf, buf.length);
//开启服务
new Server(server).start();
String msg;
//循环接收数据
while(true)
{
server.receive(packet);
msg=new String(packet.getData(),0,packet.getLength());
if(msg!=null&&msg.equals("bye"))
break;
if(msg.length()>0)
{
System.out.println("收到数据来自:("+packet.getAddress()+":"+packet.getPort()+")="+msg);
if(!users.containsKey(packet.getAddress()+":"+packet.getPort()))
{
Map map=new HashMap();
map.put("id", index);
map.put("ip", packet.getAddress());
map.put("port", packet.getPort());
userList.add(map);
users.put(packet.getAddress()+":"+packet.getPort(), index);
index++;
}
}
}
server.close();
}
}