JavaSE简单实现多线程聊天
1.1 主程序入口
在主程序入口处,通过设置MyWindow的第一个参数,如果为true则为服务器,如果为false,则为客户端,当然也可以设置第二个参数,区分客户端和服务器的窗口标题。
public class JavaMain { public static void main(String[] args) {
MyWindow w=new MyWindow(false,"QQ聊天"); //运行时将false改成true, 先启动服务端,然后再改成false启动客户端
w.setNet("192.168.1.103", 12345);
}
}
1.2 界面程序
界面程序根据主程序传来的参数不同而创建客户端和服务器窗口,根据界面的构造函数中第一个参数,isServer设置服务器窗体或者是客户端窗体。
public class MyWindow extends JFrame {
private static final long serialVersionUID = 1L;
// 定义一个成员变量
Client myClient = null;
Server myServer=null;
JTextArea area=null; // 设置默认的IP地址和端口
private String ipAddress="127.0.0.1";
private int nPort=50000; private boolean isServer=false; // 构造函数
public MyWindow(boolean isServer,String title) {
this.isServer=isServer;
setTitle(title);
setSize(300, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
initComponents();
setVisible(true);
} // 为外界提供设置IP地址和端口的方法
public void setNet(String ip,int port){
ipAddress=ip;
nPort=port; // 对通信接口初始化
initCommication();
} // 通过构造函数,将端口和文本显示区传递给myServer对象
public void initCommication(){
if (isServer) {
myServer=new Server(nPort,area);
}else{
myClient=new Client(ipAddress,nPort,area);
}
} public void initComponents() {
// 添加一个文本区
area = new JTextArea();
area.setBounds(10, 20, 260, 200);
add(area);
// 添加一个文本框
final JTextField text = new JTextField();
text.setBounds(10, 240, 260, 30);
add(text);
// 添加一个发送按钮
JButton button = new JButton("发送");
button.setBounds(10, 290, 80, 30); button.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
if (isServer) {
myServer.sendServerMsg(text.getText());
}else{
myClient.sendMsg(text.getText());
}
}
});
add(button);
}
}
1.3 服务器类
服务器类比较复杂,这里用到了内部类,内部类的好处就是能随时访问外部类的成员和方法,而无需通过传参数的方法达到目的。
// 监听主线程
public class Server extends Thread {
// 服务器Socket
private ServerSocket serverSocket = null;
private ArrayList<ServerThread> clientList = null; // 显示区
private JTextArea jTextArea = null; // 构造函数
public Server(int port, JTextArea area) {
jTextArea = area;
try {
// 开始绑定端口
serverSocket = new ServerSocket(port);
// 初始化客户端连接的列表
clientList = new ArrayList<ServerThread>();
} catch (IOException e) {
System.err.println("服务器端口初始化失败!\n");
}
jTextArea.setText("服务器成功启动,等待客户连接!\n");
start(); // 启动线程
} public void sendServerMsg(String msg) {
jTextArea.append(msg + "\n");
for (int i = clientList.size() - 1; i >= 0; i--) {
clientList.get(i).getWriter().println("服务器:" + msg);
clientList.get(i).getWriter().flush();
}
} // 线程程序
public void run() {
while (true) {
try {
// 用阻塞的方式,等待用户连接请求
Socket socket = serverSocket.accept();
// 启动一条为客户端服务的线程
ServerThread svthread = new ServerThread(socket);
svthread.start();
// 将该客户加入列表中
clientList.add(svthread); } catch (IOException e) {
e.printStackTrace();
}
}
} // 服务线程(内部类),用于处理客户端的服务线程
class ServerThread extends Thread {
// 当前正在连接的Socket
Socket socket = null;
// 当前连接的Socket的输入和输出流(数据出入口)
private PrintWriter writer = null;
private BufferedReader reader = null; // 构造函数
public ServerThread(Socket s) {
socket = s;
try {
// 获取输入输出流
reader = new BufferedReader(new InputStreamReader(
s.getInputStream()));
writer = new PrintWriter(s.getOutputStream());
// 在此可以写接收用户端的信息,解析出来(IP地址) } catch (Exception e) {
e.printStackTrace();
}
} // 获得输入流,供外界调用
public BufferedReader getReader() {
return reader;
} // 获得输出流,供外界调用
public PrintWriter getWriter() {
return writer;
} // 获得socket
public Socket getSocket() {
return socket;
} // 线程服务程序
public void run() {
// 创建一个变量,用于接收客户端发来的信息
String message = null;
while (true) {
try {
// 读取输入流
message = reader.readLine();
// 如果是下线命令
if (message.equals("Bye")) {
// 在客户端列表上删除该用户
ServerThread temp = null;
for (int i = clientList.size() - 1; i >= 0; i--) {
temp = clientList.get(i);
if (temp.getSocket().equals(socket)) {
clientList.remove(i);
}
temp.stop();
}
// 断开连接释放资源
reader.close();
writer.close();
socket.close();
return;
} else {
// 在文本区显示该消息
jTextArea.append(message + "\n");
// 将该消息广播给其他用户
broadcastMsg(message);
} } catch (Exception e) {
// TODO: handle exception
}
}
} // 广播消息
public void broadcastMsg(String msg) {
for (int i = clientList.size() - 1; i >= 0; i--) {
clientList.get(i).getWriter().println(msg);
clientList.get(i).getWriter().flush();
}
}
}
}
1.4 客户端类
客户端类比较简单,只要创建一个线程,与服务器连接即可。
public class Client extends Thread {
// 写该类的成员变量
private Socket socket=null;
private PrintWriter out=null;
private BufferedReader in=null; private JTextArea area; // 写构造函数,完成初始化
public Client(String ip,int nPort,JTextArea area){
try {
socket=new Socket(ip, nPort); } catch (UnknownHostException e) {
System.err.println("初始化失败!");
} catch (IOException e) {
System.err.println("初始化失败!");
}
start(); // 启动线程,让线程开始工作
this.area=area;
this.area.setText("初始化成功,连接上服务器!\n");
} // 发送消息
public void sendMsg(String msg){
if(socket.isConnected()==true){
out.println("客户端:"+msg);
out.flush();// 将消息推送给客户端
}
} public void run(){
while(true){
try {
// 获取客户端的输入流
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
in = new BufferedReader(isr);
// 获取客户端的输出流
out = new PrintWriter(socket.getOutputStream(), true); while(true){
// 不停的读取从服务器发来的信息
String info = in.readLine();
area.append(info + "\n");
}
} catch (Exception e) {
System.err.println("发生数据流读取错误,程序退出!");
System.exit(1);
} finally{
try {
// 结束,扫尾工作
out.close();
in.close();
socket.close();
} catch (Exception e2) {
}
}
}
}
}
1.5 运行结果
运行结果如下所示:
JavaSE简单实现多线程聊天的更多相关文章
- Python 简单的多线程聊天
# client 端 import socket ip_port = ('127.0.0.1', 8091) sk = socket.socket() sk.connect(ip_port) prin ...
- 【C++】基于socket的多线程聊天室(控制台版)
以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...
- java Socket多线程聊天程序
参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...
- 使用Servlet和JSP实现一个简单的Web聊天室系统
1 问题描述 利用Java EE相关技术实现一个简单的Web聊天室系统,具体要求如下. (1)编写一个登录 ...
- Unity3D 实现简单的语音聊天 [iOS版本]
现在很多手机游戏中的聊天系统都加入语音聊天的功能,相比于传统的文字聊天,语音聊天在MMORPG中显得尤为重要,毕竟直接口头交流总比你码字快得多了,也更直观些. 实现语音聊天的方法很多,U3D中有不少第 ...
- 一个简单的多线程Python爬虫(一)
一个简单的多线程Python爬虫 最近想要抓取拉勾网的数据,最开始是使用Scrapy的,但是遇到了下面两个问题: 前端页面是用JS模板引擎生成的 接口主要是用POST提交参数的 目前不会处理使用JS模 ...
- 【Python网络编程】多线程聊天软件程序
课程设计的时候制作的多线程聊天软件程序 基于python3.4.3 import socket import pickle import threading import tkinter import ...
- CreateThread简单那多线程编程
CreateThread简单那多线程编程 作者:vpoet mail:vpoet_sir@163.com 在进行多任务处理的时候我们往往会用到多线程技术,多线程理论上是多个线程同事处理不同的工作,但是 ...
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...
随机推荐
- D. Vitya and Strange Lesson Codeforces Round #430 (Div. 2)
http://codeforces.com/contest/842/problem/D 树 二进制(路径,每个节点代表一位) #include <cstdio> #include < ...
- opencv图片右转函数
因为需要将函数进行右转,发现opencv自带 的过于麻烦.自己写了个右转的.可以根据这个想法写出任何方向的 //函数功能,右转图片 IplImage* convertImage(IplImage* i ...
- kubernetes 之ingress
www.cnblogs.com/hellojackyleon/p/8420911.html apiVersion: extensions/v1beta1 kind: Deployment metada ...
- C++中基于成员函数是否是const重载成员函数
C++pimer中文版第四版 378页 基于const的重载 如果我们要在一个类的成员函数中定义两个函数签名完全一样的成员函数,比如display,那么可以基于是否是const成员函数来重载.比如: ...
- CSS3 box-sizing:border-box的好处
无论如何改动border,margin与padding的值,都不会导致box总尺寸发生变化.
- windows安装filebeat服务报错
cmd进入filebeat目录下 用以下命令执行: PowerShell.exe -ExecutionPolicy UnRestricted -File .\install-service-fil ...
- vue组件间的通信
组件的定义: 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.v ...
- 2017 10.25 NOIP模拟赛
期望得分:100+40+100=240 实际得分:50+40+20=110 T1 start取了min没有用,w(゚Д゚)w O(≧口≦)O T3 代码3个bug :数组开小了,一个细节没注意, ...
- AT1983 BBQ Hard
洛谷题目链接:BBQ Hard 题意翻译 有 n 个数对 \((A_i; B_i)\),求出 \[\sum_{i=1}^{n}\sum_{j=i + 1}^{n}{a_i+b_i+a_j+b_j ...
- mysql自学路线
入门: -Head First:PHP & MySQL.Lynn Beighley -MySQL必知必会 -MySQL5.5从零开始学.刘增杰 -MYSQL完全手册 (the Complete ...