在看到本文之前,如果读者没看过笔者的前文Java实现Socket网络编程(一) ,请先翻阅。在阅读本文前,读者应先具备Java的Swing编程的基础知识。
首先,我们编写服务器的界面:
JFrame mainFrame = new ServerMain();
mainFrame.setTitle("server");
mainFrame.setSize(545, 395);
// 设置显示位置为正中间
mainFrame.setLocationRelativeTo(null);
// 设置布局文件为空,以让组件可使用绝对布局setBounds
mainFrame.setLayout(null);
// 大小不可变
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
// 设置IPAddress标签
JLabel jlIP = new JLabel("IPAddress:");
jlIP.setBounds(10, 15, 70, 25);
add(jlIP);
// 设置IPAddress显示文本
JTextField jtfIP = new JTextField();
jtfIP.setText("127.0.0.1");
jtfIP.setEditable(false);
jtfIP.setBounds(80, 15, 185, 25);
jtfIP.setText(Common.IP);
add(jtfIP);
// 设置Port标签
JLabel jlPort = new JLabel("Port:");
jlPort.setBounds(10, 50, 70, 25);
add(jlPort);
// 设置Port显示文本
JTextField jtfPort = new JTextField();
jtfPort.setText("10055");
jtfPort.setEditable(false);
jtfPort.setBounds(80, 50, 185, 25);
jtfPort.setText(Common.PORT + "");
add(jtfPort);
// 设置Client标签
JLabel jlClient = new JLabel("Choose Client:");
jlClient.setBounds(15, 90, 100, 25);
add(jlClient);
// 创建Client列表
model = new DefaultListModel<>();
clientList = new JList<String>(model);
clientList.setBorder(BorderFactory.createLineBorder(Color.black));
// 设置多选模式
clientList
.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
clientList.setFocusable(true);
// 添加滚动
jpclientList = new JScrollPane(clientList);
jpclientList.setBounds(10, 115, 255, 65);
add(jpclientList);
// 设置Send Message标签
JLabel jlSendMessage = new JLabel("Send Message:");
jlSendMessage.setBounds(15, 185, 100, 25);
add(jlSendMessage);
// 设置Send Message文本
jtaSendMessage = new JTextArea();
// 激活自动换行功能
jtaSendMessage.setLineWrap(true);
// 激活断行不断字功能
jtaSendMessage.setWrapStyleWord(true);
// 设置黑色边框
jtaSendMessage.setBorder(BorderFactory.createLineBorder(Color.black));
// 添加滚动条
JScrollPane jpSendMessage = new JScrollPane(jtaSendMessage);
jpSendMessage.setBounds(10, 210, 255, 100);
add(jpSendMessage);
// 设置Connect标签
jlConnect = new JLabel("0 Connect success.");
jlConnect.setBounds(15, 320, 130, 25);
add(jlConnect);
// 设置Send Message按钮
JButton jbSendMessage = new JButton("SendMessage");
jbSendMessage.setBounds(145, 320, 120, 25);
add(jbSendMessage);
// 设置Received Message标签
JLabel jlReceivedMessage = new JLabel("Received Message:");
jlReceivedMessage.setBounds(295, 15, 130, 25);
add(jlReceivedMessage);
// 设置Received Message文本
jtaReceivedMessage = new JTextArea();
// 激活自动换行功能
jtaReceivedMessage.setLineWrap(true);
// 激活断行不断字功能
jtaReceivedMessage.setWrapStyleWord(true);
// 设置不可编辑
jtaReceivedMessage.setEditable(false);
// 设置黑色边框
jtaReceivedMessage.setBorder(BorderFactory
.createLineBorder(Color.black));
// 添加滚动条
JScrollPane jpReceivedMessage = new JScrollPane(jtaReceivedMessage);
jpReceivedMessage.setBounds(285, 40, 230, 305);
add(jpReceivedMessage);
然后,我们编写客户端界面:因客户端界面和服务器界面大体相似,笔者在此处就不粘贴代码了。值得注意的是,客户端和服务器应是两个不同的Java Project。
根据设计思路,我们为服务器创建一个ServerSocket,监听4703端口,并启动一个主监听线程,监测是否有客户端连接。
try {
// 创建监听4703端口的ServerSocket
serverSocket = new ServerSocket(Common.PORT);
// 启动一个监听线程
listenThread = new Thread(new ListenThread());
listenThread.start();
} catch (Exception e1) {
e1.printStackTrace();
}
实际上,可采用大于1024的任意端口,笔者选用4703端口,是因为此端口很少被占用,能在不同的机器上运行时不会产生端口冲突。小于1024的端口都是绑定给特定的服务,所以一般除了那些专门提供某服务的软件可以用,别的软件一般不用。
下面,我们来实现服务器主监听线程ListenThread:
// 响应一个请求
Socket clientSocket = ServerMain.serverSocket.accept();
// 创建一个子线程和客户端保持连接
new Thread(new ServerReceiverThread(clientSocket)).start();
// 添加到Socket请求队列
HashMap<Socket, Boolean> map = new HashMap<Socket, Boolean>();
map.put(clientSocket, false);
clientSockets.add(map);
通过ServerSocket的accept()方法,去响应一个连接请求,并创建一个与客户端交互的Socket对象,把Socket对象添加到请求队列,为后期发送消息做准备。同时创建一个子线程,用于接收客户端消息。