📄 server.java
字号:
//Server.java
//作者:毛伟,贾桂卿,郭威
//基于TCP的聊天软件服务器端
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.lang.*;
/*=============================================================
描述:实现服务器端界面
创建一个套接字,绑定了8080端口。
创建侦听线程,监测是否有客户端请求连接
创建接收线程,接收客户端发来的数据
创建发送线程,向客户端发送数据
==============================================================*/
public class Server extends JFrame
{
public JTextField tField = new JTextField("输入");
public JTextArea tArea = new JTextArea("聊天记录:", 40, 20);
public JScrollPane scrollArea = new JScrollPane(tArea,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
public JPanel buttons=new JPanel();
public JButton send = new JButton("发送");
public JButton clear = new JButton("清除");
public JButton disconn = new JButton("断开");
public ServerSocket server;
public Socket connectionSocket;
public Object sendObj=new Object();
public Thread waitConnect;
public Thread waitSend;
public Thread waitRcv;
/*===============================================
描述:Server类的构造函数,用来创建服务器端界面
================================================*/
public Server(String title)
{
super(title);
Container cp = getContentPane();
ButtonHandler handler = new ButtonHandler();
tField.addActionListener(handler);
send.addActionListener(handler);
clear.addActionListener(handler);
disconn.addActionListener(handler);
BorderLayout layout=new BorderLayout();
cp.setLayout(layout);
cp.add(BorderLayout.WEST,scrollArea);
cp.add(BorderLayout.SOUTH,tField);
tField.setEnabled(false);
cp.add(BorderLayout.CENTER,buttons);
FlowLayout layout1 = new FlowLayout();
buttons.setLayout(layout1);
buttons.add(send);
send.setEnabled(false);
buttons.add(clear);
clear.setEnabled(false);
buttons.add(disconn);
disconn.setEnabled(false);
setSize(348, 200);
setVisible(true);
}
/*===============================================
描述:创建套接字,启动侦听线程
================================================*/
public void runServer()
{
try
{
server = new ServerSocket(8080);
waitConnect = new Thread(new WaitForConnect(this));
waitConnect.start();
}
catch(IOException iException)
{
tArea.append("\n打开通信端口失败!");
iException.printStackTrace();
}
}
/*===============================================
描述:启动服务器端接收和发送线程
================================================*/
public void initialSendRcvThread()
{
tField.setEnabled(true);
send.setEnabled(true);
clear.setEnabled(true);
disconn.setEnabled(true);
waitSend = new Thread(new SendThread(this));
waitSend.start();
waitRcv = new Thread(new RcvThread(this));
waitRcv.start();
}
/*===============================================
描述:Server类的入口点函数,也是整个服务器端的入口点
================================================*/
public static void main(String[] args)
{
Server frame1=new Server("服务器");
frame1.addWindowListener(new WindowClose());
frame1.runServer();
}
/*===============================================
描述:清除函数,在服务器端终止与客户端通信时,
终止各类线程,关闭建立的套接字连接。
================================================*/
public void cleanAll() throws IOException
{
if(waitRcv != null)
{
waitRcv.stop();
waitRcv=null;
}
if(waitSend != null)
{
waitSend.stop();
waitSend=null;
}
if(waitConnect != null)
{
waitConnect.stop();
waitConnect=null;
}
tArea.append("\n断开与"+connectionSocket.getInetAddress().getHostName()+"连接!");
tArea.setCaretPosition(tArea.getText().length());
if(connectionSocket != null)
{
connectionSocket.close();
connectionSocket=null;
}
if(server != null)
{
server.close();
server = null;
}
send.setEnabled(false);
clear.setEnabled(false);
disconn.setEnabled(false);
}
/*===============================================
描述:事件监听函数,监测并处理用户操作时引发的事件。
================================================*/
private class ButtonHandler implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
if(e.getSource() == tField)
{
sendData(e.getActionCommand());
synchronized(sendObj)
{
sendObj.notify();
}
}
else if(e.getSource() == send)
{
sendData(tField.getText());
synchronized(sendObj)
{
sendObj.notify();
}
}
else if(e.getSource() == clear)
{
tArea.setText("聊天记录:");
tField.setText("");
}
else if(e.getSource() == disconn)
{
try
{
cleanAll();
runServer();
}
catch (IOException io)
{
tArea.append("\n 关闭通信端口失败!");
}
}
}
}
public void sendData(String message)
{
tArea.append("\n服务器>>"+message);
tArea.setCaretPosition(tArea.getText().length());
}
}
/*===============================================
描述:用户关闭服务器端界面的事件处理类
================================================*/
class WindowClose extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
/*===============================================
描述:侦听线程类,侦听指定的端口,监测是否有客户端
请求连接
================================================*/
class WaitForConnect implements Runnable
{
Server serverObj;
public WaitForConnect(Server serverObj)
{
this.serverObj=serverObj;
}
public void run()
{
try
{
serverObj.tArea.append("\n等待连接!");
serverObj.tArea.setCaretPosition(serverObj.tArea.getText().length());
serverObj.connectionSocket = serverObj.server.accept();
serverObj.tArea.append("\n与 " + serverObj.connectionSocket.getInetAddress().getHostName()+" 建立连接");
serverObj.tArea.setCaretPosition(serverObj.tArea.getText().length());
serverObj.initialSendRcvThread();
}
catch(EOFException eException)
{
serverObj.tArea.append("\n客户端结束会话!");
eException.printStackTrace();
}
catch(IOException iException)
{
serverObj.tArea.append("\n连接意外失败!");
iException.printStackTrace();
}
}
}
/*===============================================
描述:接收线程类,接收来自客户端传来的数据
================================================*/
class RcvThread implements Runnable
{
ObjectInputStream input;
Server serverObj;
public RcvThread(Server serverObj)
{
this.serverObj=serverObj;
try
{
input = new ObjectInputStream(serverObj.connectionSocket.getInputStream());
}
catch(IOException iException)
{
serverObj.tArea.append("\n初始化接收失败!");
}
}
public void run()
{
while(true)
{
try
{
String str = (String)input.readObject();
serverObj.tArea.append("\n客户端>>"+str);
serverObj.tArea.setCaretPosition(serverObj.tArea.getText().length());
}
catch(ClassNotFoundException e)
{
serverObj.tArea.append("\n收到未知类型数据包!");
}
catch(IOException io)
{
}
}
}
}
/*===============================================
描述:发送线程类,向客户端发送用户需要传递的数据
================================================*/
class SendThread implements Runnable
{
ObjectOutputStream output;
Server serverObj;
public SendThread(Server serverObj)
{
this.serverObj=serverObj;
try
{
output=new ObjectOutputStream(serverObj.connectionSocket.getOutputStream());
output.flush();
}
catch(IOException iException)
{
iException.printStackTrace();
serverObj.tArea.append("\n初始化输出!");
}
}
public void run()
{
while(true)
{
synchronized(serverObj.sendObj)
{
try
{
serverObj.sendObj.wait(0);
output.writeObject(serverObj.tField.getText());
}
catch(InterruptedException e)
{
}
catch(IOException io)
{
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -