//【例10.4】 多客户的TCP Socket通信。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
public class ChatServerMultiSocketJFrame extends JFrame implements ActionListener
{ //服务端聊天室的图形用户界面
private String name; //网名
private JComboBox combox; //输入IP地址或域名的组合框
private JTextField text; //输入端口的文本行
private JTabbedPane tab; //选项卡窗格,每页与一个Socket通信
public ChatServerMultiSocketJFrame(int port, String name) throws IOException
{ //port指定初始端口
super("聊天室 "+name+" "+InetAddress.getLocalHost()+" : "+port);
this.setBounds(320,240,440,240);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JToolBar toolbar = new JToolBar(); //工具栏
this.getContentPane().add(toolbar,"North");
toolbar.add(new JLabel("主机"));
combox = new JComboBox();
combox.addItem("127.0.0.1");
toolbar.add(combox);
combox.setEditable(true);
toolbar.add(new JLabel("端口"));
text = new JTextField("2002");
toolbar.add(text);
JButton button_connect = new JButton("请求连接");
button_connect.addActionListener(this);
toolbar.add(button_connect);
tab = new JTabbedPane(); //选项卡窗格
this.getContentPane().add(tab);
this.setVisible(true);
this.name = name;
while (true)
{
Socket client=new ServerSocket(port).accept(); //等待接收客户端的连接申请
tab.addTab(name, new TabPageJPanel(client)); //tab添加新页,页中添加一个内部类面板
tab.setSelectedIndex(tab.getTabCount()-1); //tab指定新页为选中状态
port++; //在下一个端口等待下一个客户端
}
}
public void actionPerformed(ActionEvent e) //单击"请求连接"按钮
{
if (e.getActionCommand()=="请求连接")
{
String host = (String)combox.getSelectedItem();
int port = Integer.parseInt(text.getText());
try
{
tab.addTab(name, new TabPageJPanel(new Socket(host, port))); //tab添加新页
tab.setSelectedIndex(tab.getTabCount()-1); //tab指定新页为选中状态
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
//面板内部类,每个对象表示选项卡窗格的一页,包含一个Socket和一个线程
private class TabPageJPanel extends JPanel implements Runnable, ActionListener
{
Socket socket;
Thread thread;
JTextArea text_receiver; //显示对话内容的文本区
JTextField text_sender; //输入发送内容的文本行
JButton buttons[]; //发送、离线、删除页按钮
PrintWriter cout; //字符输出流对象
int index; //当前页在tab中的序号
TabPageJPanel(Socket socket)
{
super(new BorderLayout());
this.text_receiver = new JTextArea();
this.text_receiver.setEditable(false);
this.add(new JScrollPane(this.text_receiver));
JPanel panel = new JPanel();
this.add(panel,"South");
this.text_sender = new JTextField(16);
panel.add(this.text_sender);
this.text_sender.addActionListener(this);
String strs[]={"发送","离线","删除页"};
buttons = new JButton[strs.length];
for (int i=0; i<buttons.length; i++)
{
buttons[i] = new JButton(strs[i]);
panel.add(buttons[i]);
buttons[i].addActionListener(this);
}
buttons[2].setEnabled(false);
this.socket = socket;
this.thread = new Thread(this);
this.thread.start();
}
public void run()
{
try
{
this.cout = new PrintWriter(socket.getOutputStream(),true);
this.cout.println(name); //发送自己网名给对方
BufferedReader cin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String name=cin.readLine(); //接收对方网名
index = tab.getSelectedIndex();
tab.setTitleAt(index, name); //将对方网名设置为当前页标题
String aline= cin.readLine();
while (aline!=null && !aline.equals("bye"))
{
tab.setSelectedIndex(index); //收到对方信息时,显示该页
text_receiver.append(aline+"\r\n");
Thread.sleep(1000);
aline= cin.readLine();
}
cin.close();
cout.close();
socket.close();
buttons[0].setEnabled(false); //接收方的发送按钮无效
buttons[1].setEnabled(false); //接收方的离线按钮无效
buttons[2].setEnabled(true); //接收方的删除按钮无效
}
catch(Exception e)
{
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent e) //单击tab页上的"发送"等按钮
{
if (e.getSource()==buttons[0]) //发送
{
this.cout.println(name+" 说:"+text_sender.getText());
text_receiver.append("我说:"+text_sender.getText()+"\n");
text_sender.setText("");
}
if (e.getSource()==buttons[1]) //离线
{
text_receiver.append("我离线\n");
this.cout.println(name+"离线\n"+"bye");
buttons[0].setEnabled(false); //发送方的发送按钮无效
buttons[1].setEnabled(false); //发送方的离线按钮无效
buttons[2].setEnabled(true); //发送方的删除按钮无效
}
if (e.getSource()==buttons[2])
tab.remove(tab.getSelectedIndex()); //删除tab当前页
}
}//TabPageJPanel内部类结束
public static void main(String args[]) throws IOException
{
new ChatServerMultiSocketJFrame(2001, "花仙子"); //启动服务端,约定端口号,指定网名
}
}