要求:
(1)用Socket编程实现服务器端和客户端程序的编写。
(2)服务器端只负责好友列表的刷新,不负责客户端聊天信息的转发。
代码实现:
服务器端:
package 第十三周;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
public class Server extends JFrame {
JLabel jl = new JLabel("开始监听9999端口!");
JButton jb = new JButton("退出");
JPanel jp_1 = new JPanel();
JPanel jp_2 = new JPanel();
JPanel jp_3 = new JPanel();
ServerSocket s = null;
Socket nsocket[] = new Socket[50];
String str = "";
StringBuilder sb = new StringBuilder(str);
Border bevelBorder = new BevelBorder(BevelBorder.RAISED, Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK);
public Server() {
super("Socket聊天室服务器端");
init();
this.setSize(350, 250);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void init() {
jp_1.setLayout(new BorderLayout());
jp_2.setBorder(bevelBorder);
jp_3.add(jb);
jl.setHorizontalAlignment(JLabel.RIGHT);
jp_1.add(jl, BorderLayout.NORTH);
jp_1.add(jp_2);
jp_1.add(jp_3, BorderLayout.SOUTH);
jb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int i = JOptionPane.showConfirmDialog(jb, "您确定要退出吗?");
if(i == 0) {
System.exit(0);
}
}
});
this.add(jp_1);
}
public static void main(String[] args) throws Exception {
new Server().MoreServer();
}
public void MoreServer() {
try {
s = new ServerSocket(9999);
System.out.println("服务器已经开启...");
int i = 0;
while(true) {
Socket socket = s.accept();
int j = 0;
nsocket[i++] = socket;
String addr = socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
System.out.println("客户" + addr + "访问!");
sb.append(addr).append(",");
str = sb.toString();
for(j = 0; j < i; j++) {
PrintStream ps = new PrintStream(nsocket[j].getOutputStream());
ps.println(str);
}
new ServerReaderThread1(socket, nsocket, str, i).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerReaderThread1 extends Thread {
Socket socket;
Socket nsocket[];
String addr;
Scanner sc;
int cnt;
public ServerReaderThread1(Socket socket, Socket nsocket[], String str, int cnt) {
super();
this.socket = socket;
this.nsocket = nsocket;
addr = str;
this.cnt = cnt;
}
@Override
public void run() {
try {
sc = new Scanner(socket.getInputStream());
while(true) {
String str = sc.nextLine();
if("exit".equalsIgnoreCase(str)) {
addr = sc.nextLine();
String arr[] = addr.split(",");
int j = 0;
for(int i = 0; i < arr.length; i ++) {
if(nsocket[i] == socket) {
j = i;
}
}
for(int i = j; i < arr.length; i++) {
if(i != arr.length - 1) {
arr[i] = arr[i + 1];
}
else {
arr[i] = "";
}
}
StringBuilder sb1 = new StringBuilder();
for(int i = 0; i < arr.length - 1; i++) {
sb1.append(arr[i]).append(",");
}
sb = sb1;
addr = sb1.toString();
for(int p = 0; p < nsocket.length; p++) {
PrintStream ps = new PrintStream(nsocket[p].getOutputStream());
ps.println(addr);
}
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.Vector;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class ChatClient extends JFrame {
Vector v = new Vector();
Socket socket;
JList<String> jList = new JList<String>(v);
JLabel jl = new JLabel("连接到127.0.0.1:9999端口!");
JTextArea jta_1 = new JTextArea(10, 25);
JTextArea jta_2 = new JTextArea(2, 42);
JButton jb_sent = new JButton("发送");
JButton jb_clear = new JButton("清空");
JPanel jp_1 = new JPanel();
JPanel jp_2 = new JPanel();
JPanel jp_3 = new JPanel();
JPanel jp_4 = new JPanel();
String s1;
public ChatClient() throws Exception {
super("聊天室客户端");
init();
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void init() {
//组装视图
this.setLayout(new BorderLayout());
this.setSize(500, 380);
//组装顶部
jList.setFixedCellWidth(160);
jList.setFixedCellHeight(37);
TitledBorder tb_1 = new TitledBorder("好友列表");
jList.setBorder(tb_1);
jp_1.add(jList);
TitledBorder tb_2 = new TitledBorder("聊天记录");
jta_1.setBorder(tb_2);
jl.setHorizontalAlignment(JLabel.RIGHT);
jp_2.setLayout(new BorderLayout());
jp_2.add(jl, BorderLayout.NORTH);
jp_2.add(new JScrollPane(jta_1));
//组装底部
TitledBorder tb_3 = new TitledBorder("请输入文字:");
jta_2.setBorder(tb_3);
jp_4.add(jb_sent);
jp_4.add(jb_clear);
Box vBox = Box.createVerticalBox();
vBox.add(jta_2);
vBox.add(jp_4);
jp_3.add(vBox);
this.add(jp_1, BorderLayout.WEST);
this.add(jp_2);
this.add(jp_3, BorderLayout.SOUTH);
}
public static void main(String[] args) throws Exception {
new ChatClient().MoreClient();
}
public void MoreClient() throws Exception {
Socket socket = new Socket("127.0.0.1", 9999);
Scanner sc = new Scanner(System.in);
PrintWriter pm = new PrintWriter(socket.getOutputStream());;
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
pm.println("exit");
pm.flush();
pm.println(s1);
pm.flush();
}
});
while(true) {
Scanner sc1 = new Scanner(socket.getInputStream());
s1 = sc1.nextLine();
if(!v.contains(s1)) {
add(s1);
}
}
}
public void add(String str) {
v.clear();
String arr[] = new String[50];
arr = str.split(",");
for(String s : arr) {
v.addElement(s);
jList.setListData(v);
}
}
}
运行过程:
(1)首先启动服务端
(2)接着启动第一个客户端,好友列表刷新出第一个在线用户
(3)再启动第二个客户端,两个客户端的好友列表此时都有两个在线用户
(4)退出第二个启动的客户端,此时第一个启动的客户端的列表中只剩一个在线用户
(5)再启动第三个客户端,此时两个在线的客户端的好友列表又存在两个在线用户
(6)运行结果大致如上。