心得感悟
学会socket方法后,没想到聊天功能的实现这么简单,不过说是简单,里面有些东西我还是没有完全弄懂,可能再多写几遍就明白了吧。即使班里大佬很多,也要做一个努力的菜鸡。
内容简概
- 一、使⽤多线程实现对聊
- 二、实现群聊
- 三、运行效果
具体内容
一、使⽤多线程实现对聊
1. 首先我们分析一下程序的结构框架
在上一篇文章中,我们实现了服务器端向客户端的文字信息传输,那么如果想要实现服务器端和客户端的数据互传该怎么办呢?说到需要多个设备同时操作,就联想到之前讲过的多线程
。
2. 先写一个客户端的主线程,将
终端的输入发送给服务器端
。用主线程来处理终端输入,这样的好处是防止终端卡顿,因为主线程总是被优先运行。
class Client{
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
// 用一个子线程处理服务器端数据
new Thread(new ClientThread(socket)).start();
// 主线程处理终端输入发送给服务器端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
ps.println(line);
}
}
}
3. 接下来再编写子线程。创建一个子线程处理客户端接收服务器端数据
。
class ClientThread implements Runnable{
private Socket socket;
// 保存socket对象
public ClientThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
// 获取服务器端的输入流对象
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 读取数据
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("网络出错 请重新登录");
System.exit(-1);
}finally {
try {
if(br != null) {
br.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
}
}
}
}
4. 再然后是创建服务器端的主线程,将终端的输入发送给客户端
。
class Server{
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888);
// 获取客户端的socket
Socket socket = ss.accept();
// 创建子线程 处理客户输入信息
new ServerThread(socket).start();
// 终端输入流对象
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
// 客户端输出流
PrintStream ps = new PrintStream(socket.getOutputStream());
// 读取终端的输入 将输入输出给客户端
String line = null;
while ((line = keyin.readLine()) != null){
ps.println(line);
}
}
}
5.最后创建一个服务器端的子线程,处理服务器端接收客户端数据
。
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("网络异常 请重新登陆");
System.exit(-1);
} finally {
// 关闭输入输出流
// 关闭对应的socket链接
try {
if (br != null){
br.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二、实现群聊
1. 首先我们分析一下程序的结构框架
现在我们需要向多个客户端发送信息,即一个客户端输入数据时,服务器端需要将数据转发给该客户端和其他客户端。为什么要发回给输入的客户端呢?回想一下,QQ聊天中是不是输入框和聊天框是分开的?自己发出去的消息还是会显示在自己的聊天界面中。
如何实现同时向多个客户端发送数据?
需要批量管理时就联想到列表或数组,这里要存储的是多个客户端对象,故我们可以通过列表ArrayList来实现批量管理。分析到这,我们发现客户端的代码(相比对聊)是不需要修改的,只需要修改服务器端的代码即可
。
2. 在Server⾥添加数组和监听客户端连接
class Server{
// 保存每一个连接过来的socket对象
public static ArrayList<Socket> sockets = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888);
// 不停地等待客户端来连接
while (true){
Socket socket = ss.accept();
// 当有客户端连接过来了 就保存
sockets.add(socket);
// 开启一个线程处理每个客户端的输入
new ServerThread(socket).start();
}
}
}
3. ServerThread⾥实现群发
后半段异常的处理与对聊程序完全一致。
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
// 群发消息
// 遍历Server维护的数组
for(Socket s:Server.sockets){
// 向socket对应的客户端发送消息
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(line);
}
}
三、运行效果
顺序为对聊 → 群聊
在这里我用本机的多个客户端模拟群聊,你也可以找好友要IP地址,选择一个人作为服务器端,其他人作为客户端来模拟。