`
ggxin
  • 浏览: 41203 次
  • 性别: Icon_minigender_1
  • 来自: 广西
社区版块
存档分类
最新评论

Java写的P2P聊天程序

阅读更多

这几天偶然想研究下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();
	}

}

 

0
5
分享到:
评论
3 楼 ggxin 2013-04-16  
内部对于p2p似乎用途不是很大~
2 楼 wzjin 2013-04-16  
osacar 写道
我也正想写一个来内部用呢。

内部可以用飞鸽传书,也有java版的。
1 楼 osacar 2013-04-16  
我也正想写一个来内部用呢。

相关推荐

Global site tag (gtag.js) - Google Analytics