正在做一个Java聊天程序有个问题想不明白,是这样的假如有A,B,C,D四个人分别位于四台不同的主机上当他们都运行程序后,A先和C聊天于是C的主机上就会有一个与A对话的聊天窗口,然后B也和C聊天这时C的主机上也会有一个和B对话的聊天窗口,这两次聊天C都是聊天的被动方也就是被呼叫的一方。假如A和C聊天用的是2121端口B和C聊天用的是2122端口这样肯定没问题C在不同的端口上接收不同聊天对象发来的消息然后再显示在不同的聊天窗口中,但是如果在A和C聊天之前如果C正在和D聊天呢?而且用的端口是2121(起始端口号,和第一个聊天对象聊天所使用的端口以后端口递增C在和D聊天之前没有聊天请求)那么A和C之间的通信岂不是要阻断了嘛,我搞不明白的是C怎样才知道A是在哪一个端口上发送消息的然后才在这个端口上接收消息,我想的办法是在A和C聊天之前先通过一种方法协议一下消息的收发端口然后在在协议好的端口上进行消息的传递但是在协议之前A和C主机上的聊天会话是不同的比如A上正有3个聊天会话而C上有4个聊天会话这时A上的端口号递增到了2123而C上的递增到了2124,如果A主动和C联系那么A应该会以最小的2123为协议端口来和C建立连接但是这是在C主机上2123端口已经被占用了这样这次协议就不会成功而且A并不知道C主机的端口递增到了哪里。上面的方法是每当建立一个聊天会话窗口后就会递增一个端口监听消息,那又或者所有的消息都在一个端口上收发,C从ABD那里接收到的消息都是在2121上监听的,也就是软件在设计的时候固定一个端口2121专门用来收发聊天消息,但是这样的话消息的接收端要怎么区分哪个消息是从哪里来的呢,C接收B的消息是在2121而接收A的消息也是在2121.正确的做法到底是每一个聊天都设立一个端口监听还是所有的聊天都用一个端口监听
呵 可能写的有些拗口 希望大侠们能明白我的意思
呵 可能写的有些拗口 希望大侠们能明白我的意思
用Map或临时表保存用户名和对应的端口和Ip。Map<用户名,[端口,IP]数组>
每个用户对应一个用户名,该用户名唯一,其登录后,将其用户名作为key,当前所用的端口和IP组成数组保存到一个服务器端的一个公用的Map或临时表中。
当A向B发送消息的时候,A只需要知道发给B,而服务器端会根据用户名B遍历Map或者表,来取得B的端口号和IP,这样就可以把A的消息发给B了。
import java.io.*;
import java.net.*;
import java.util.*;public class Talking extends Thread{ Socket s;
Map sockets;
String name;
public Talking(String n, Socket s,Map m) {
super();
this.s=s;
this.sockets=m;
this.name=n;
}
public void run(){
try{
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
while(true){
String text=in.readLine();
if(text==null)return;
StringTokenizer st=new StringTokenizer(text,"$");
String from=st.nextToken();
String to=st.nextToken();
if(to.equals("All")){
Collection values=sockets.values();
Iterator it=values.iterator();
while(it.hasNext()){
Socket s1=(Socket) it.next();
PrintWriter out=new PrintWriter(s1.getOutputStream());
out.println("Text:"+text);
out.flush();
}
}else{
Socket s2=(Socket) sockets.get(to);
PrintWriter out=new PrintWriter(s2.getOutputStream());
out.println("Text:"+text);
out.flush();
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
try{
this.sockets.remove(name);
Collection value=sockets.values();
Iterator it=value.iterator();
while(it.hasNext()){
Socket s2=(Socket) it.next();
PrintWriter pw=new PrintWriter(s2.getOutputStream());
pw.println("Del:"+name);
pw.flush();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
聊天室服务器端 服务类:package server;
import java.io.*;
import java.net.*;
import java.util.*;public class TalkRoomServer {
public static void main(String args[]) throws Exception{
ServerSocket ss=new ServerSocket(9000);
Map sockets=new HashMap();
while(true){
Socket s=ss.accept();
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter out=new PrintWriter(s.getOutputStream());
String name=in.readLine();
String IP=s.getInetAddress().toString();
System.out.println(name+":"+IP);
Collection valuse=sockets.values();
Iterator it=valuse.iterator();
while(it.hasNext()){
Socket s1=(Socket) it.next();
PrintWriter pw=new PrintWriter(s1.getOutputStream());
pw.println("Add:"+name+IP);
pw.flush();
}
sockets.put(name, s);
Set names=sockets.keySet();
it=names.iterator();
while(it.hasNext()){
String loginedUser=(String) it.next();
out.println("Add:"+loginedUser+IP);
out.flush();
}
Thread tt=new Talking(name,s,sockets);
tt.start();
}
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import java.util.*;public class TalkRoomClient extends Thread{
JFrame frame;
JTextArea jta;
JTextField jtf;
JComboBox jcb;
JDialog jd;
String name;
Socket s;
BufferedReader in;
PrintWriter out;
public TalkRoomClient(){super();}
public TalkRoomClient(String n,String ipad){
this.name=n;
String ip="localhost";
if(ipad!=null)ip=ipad;
if(name.length()==0)name="Never";
frame=new JFrame("聊天室->"+name);
frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
jta=new JTextArea();
jta.setEditable(false);
jta.setLineWrap(true);
jta.setBackground(Color.WHITE);
jta.setFont(Font.getFont("bold"));
jta.setForeground(Color.BLACK);
JScrollPane jsp=new JScrollPane(jta);
final JScrollBar jsb=jsp.getVerticalScrollBar();
frame.add(jsp,"Center");
jtf=new JTextField(20);
jcb=new JComboBox();
jcb.addItem("All");
JPanel jp=new JPanel();
jp.add(jcb);
jp.add(jtf);
frame.add(jp,"South");
frame.setVisible(true);
try{
s=new Socket(ip,9000);
in=new BufferedReader(new InputStreamReader(s.getInputStream()));
out=new PrintWriter(s.getOutputStream());
out.println(name);
out.flush();
}catch(IOException e){
e.printStackTrace();
}
jtf.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String text=jtf.getText();
jtf.setText("");
if(text.length()==0){
new JOptionPane().showMessageDialog(frame, "不允许消息为空!");
}else if(text.contains("hehe")){
new JOptionPane().showMessageDialog(frame, "聊天室中禁用敏感词汇!");
}else{
String to=(String) jcb.getSelectedItem();
if(to.equals("All")){
out.println(name+"$"+to+"$"+text);
out.flush();
}else{
jta.append(name+":>"+text+"\n");
out.println(name+"$"+to+"$"+text);
out.flush();
}
}
jsb.setValue(jta.getHeight());
}
});
}
public static void main(String args[]) throws Exception{
final JFrame jf=new JFrame("选择服务器");
jf.setLocation(400,200);
jf.setSize(250,210);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel jp=new JPanel();
final JTextField ip=new JTextField(20);
ip.setText("localhost");
JButton jb=new JButton("确定");
JLabel j1=new JLabel("服务器地址");
JLabel j2=new JLabel("聊天昵称");
final JTextField nicheng=new JTextField(20);
jp.add(j1);
jp.add(ip);
jp.add(j2);
jp.add(nicheng);
jp.add(jb);
jf.add(jp,BorderLayout.CENTER);
jf.setVisible(true);
jb.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent arg0){
String ipaddr=ip.getText();
Thread trc=new TalkRoomClient(nicheng.getText(),ipaddr);
trc.start();
jf.dispose();
}
});
}
public void run(){
try{
while(true){
String text=in.readLine();
StringTokenizer st=new StringTokenizer(text,":");
String type=st.nextToken();
String tx=st.nextToken();
if(type.equals("Add")){
System.out.println(tx);
StringTokenizer ipadr=new StringTokenizer(tx,"/");
String user = ipadr.nextToken();
if(!(this.name.equals(user))){
this.jcb.addItem(user);
}
this.jta.append(user+" "+ipadr.nextToken()+" 上线了!\n");
}
if(type.equals("Del")){
jcb.removeItem(tx);
jta.append(tx+" 下线了!\n");
}
if(type.equals("Text")){
StringTokenizer ss=new StringTokenizer(tx,"$");
String from=ss.nextToken();
String to=ss.nextToken();
String txt=ss.nextToken();
jta.append(from+":>"+txt+"\n");
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}