title: Java多线程实现多客户端的通信
date: 2019-05-05 12:50:00
Java多线程实现多客户端的通信
昨天学了Java中网络支持Socket应用,写了一个基于TCP通信的简陋的登录案例,代码如下:
服务器端:
package com.youdian.singinscoket;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/***
* 基于TCP协议的Socket,实现用户登录
* 服务器端
* @author hkq
*
*/
public class Servert {
public static void main(String[] args) {
try {
//1.创建一个服务器端的Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket=new ServerSocket(8088);
//2.调用accept()方法开始监听.
System.out.println("服务器端启动,等待客户端连接");
Socket socket= serverSocket.accept();
//3.获取字节输入流,并读取客户端信息
InputStream is=socket.getInputStream();
//4.将字节流装换为字符流,好处是提高读取的效率
InputStreamReader isr=new InputStreamReader(is);
//5.搭配使用,为字符输入流添加缓冲
BufferedReader br=new BufferedReader(isr);
//6.定义String类型的info,循环读取客户端信息并在控制台输出
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("服务器端接收到客户端数据为:"+info);
}
//7.关闭socket输入流
socket.shutdownInput();
//8.获取输出流,响应客户端的请求
OutputStream os =socket.getOutputStream();
//将字节输出流转换为打印输出流
PrintWriter pw=new PrintWriter(os);
//服务器端向客户端发送响应信息
pw.write("登录成功,欢迎你");
//调用flush()方法刷新缓存
pw.flush();
//9.关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端:
package com.youdian.singinscoket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/***
* 客户端
* @author hkq
*
*/
public class Client {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定`服务器地址和端口
Socket socket=new Socket("127.0.0.1", 8088);
//2.连接建立后,通过获取字节输出流读取服务器发送信息
OutputStream os =socket.getOutputStream();
//将字节输出流转换为打印输出流
PrintWriter pw=new PrintWriter(os);
//向服务器端发送用户信息请求
pw.write("用户名: admin;密码: 123");
//刷新缓存
pw.flush();
//关闭scoket的输出流
socket.shutdownOutput();
//获取输入流,并读取服务器端的响应信息
InputStream is=socket.getInputStream();
//将字节流装换为字符流,好处是提高读取的效率
InputStreamReader isr=new InputStreamReader(is);
//搭配使用,为字符输入流添加缓冲
BufferedReader br=new BufferedReader(isr);
//定义String类型的info,循环读取服务器信息响应并在控制台输出
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("客户端接收到服务器端数据为:"+info);
}
//关闭所有资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行的时候,一定是服务器端的代码先运行,因为客户端的代码先运行会因为找不到服务器端的出现错误提示.....
其实,实际开发中,不可能如上述代码实现服务器端和客户端的通信,因为这个只是点对点的通信方式,不可能为了一个客户端通信单独用一个服务器(有钱任性的,当我没说哈!!!土豪交个朋友!)好了,言归正传,使用多线程实现多客户端的通信,下面直接在上述代码上更改......
创建一个serverThread类继承Thread类,用来处理服务器线程,代码如下:
package com.youdian.singinscoket;
/***
* 服务器线程处理类
* @author hkq
*
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread {
//和本线程相关的Socket
Socket socket=null;
public ServerThread(Socket socket) {
this.socket=socket;
}
//线程执行的操作,响应客户端的请求
public void run() {
InputStream is=null;
InputStreamReader isr =null;
BufferedReader br=null;
PrintWriter pw=null;
OutputStream os=null;
try {
//获取字节输入流,并读取客户端信息
is=socket.getInputStream();
//将字节流装换为字符流,好处是提高读取的效率
isr=new InputStreamReader(is);
//5.搭配使用,为字符输入流添加缓冲
br=new BufferedReader(isr);
//6.定义String类型的info,循环读取客户端信息并在控制台输出
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("服务器端接收到客户端数据为:"+info);
}
//7.关闭socket输入流
socket.shutdownInput();
//8.获取输出流,响应客户端的请求
os =socket.getOutputStream();
//将字节输出流转换为打印输出流
pw=new PrintWriter(os);
//服务器端向客户端发送响应信息
pw.write("登录成功,欢迎你");
//调用flush()方法刷新缓存
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//如果为空,关闭资源
if (pw!=null)
pw.close();
if(os!=null)
os.close();
if(br!=null)
br.close();
if (isr!=null)
isr.close();
if(is!=null)
is.close();
if(socket!=null)
socket.close();
} catch (Exception e2) {
}
}
}
}
服务器端代码修改为,如下:
package com.youdian.singinscoket;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/***
* 基于TCP协议的Socket,实现用户登录
* 服务器端
* @author hkq
*
*/
public class Servert {
public static void main(String[] args) {
try {
//1.创建一个服务器端的Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket=new ServerSocket(8088);
Socket socket=null;
int count=0;
System.out.println("服务器端启动,等待客户端连接");
//使用一个死循环监听
while(true) {
//调用accept()方法开始监听,等待客户端的连接
socket= serverSocket.accept();
//创建一个新的线程
ServerThread serverThread=new ServerThread(socket);
//启动线程
serverThread.start();
count++;//统计客户端数量
System.out.println("当前连接客户端数量:"+count);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户端不变,多创建一个客户端类
package com.youdian.singinscoket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/***
* 客户端
* @author hkq
*
*/
public class Client2 {
public static void main(String[] args) {
try {
//1.创建客户端Socket,指定`服务器地址和端口
Socket socket=new Socket("127.0.0.1", 8088);
//2.连接建立后,通过获取字节输出流读取服务器发送信息
OutputStream os =socket.getOutputStream();
//将字节输出流转换为打印输出流
PrintWriter pw=new PrintWriter(os);
//向服务器端发送用户信息请求
pw.write("用户名: root;密码:5618 ");
//刷新缓存
pw.flush();
//关闭scoket的输出流
socket.shutdownOutput();
//获取输入流,并读取服务器端的响应信息
InputStream is=socket.getInputStream();
//将字节流装换为字符流,好处是提高读取的效率
InputStreamReader isr=new InputStreamReader(is);
//搭配使用,为字符输入流添加缓冲
BufferedReader br=new BufferedReader(isr);
//定义String类型的info,循环读取服务器信息响应并在控制台输出
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("客户端接收到服务器端数据为:"+info);
}
//关闭所有资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
代码运行结果:
多线程改造完成,实现多客户端与服务器端通信...多线程的本质就是让程序运行占用的资源最优化处理