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简单实现多线程聊天的更多相关文章

  1. Python 简单的多线程聊天

    # client 端 import socket ip_port = ('127.0.0.1', 8091) sk = socket.socket() sk.connect(ip_port) prin ...

  2. 【C++】基于socket的多线程聊天室(控制台版)

    以前学习socket网络编程和多线程编程的时候写的一个练手程序 聊天室基本功能: 1.用户管理:登录,注册,登出,修改用户名,修改密码 2.聊天室功能:群聊,私聊,获取在线用户列表,获取所有用户列表 ...

  3. java Socket多线程聊天程序

    参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...

  4. 使用Servlet和JSP实现一个简单的Web聊天室系统

    1 问题描述                                                利用Java EE相关技术实现一个简单的Web聊天室系统,具体要求如下. (1)编写一个登录 ...

  5. Unity3D 实现简单的语音聊天 [iOS版本]

    现在很多手机游戏中的聊天系统都加入语音聊天的功能,相比于传统的文字聊天,语音聊天在MMORPG中显得尤为重要,毕竟直接口头交流总比你码字快得多了,也更直观些. 实现语音聊天的方法很多,U3D中有不少第 ...

  6. 一个简单的多线程Python爬虫(一)

    一个简单的多线程Python爬虫 最近想要抓取拉勾网的数据,最开始是使用Scrapy的,但是遇到了下面两个问题: 前端页面是用JS模板引擎生成的 接口主要是用POST提交参数的 目前不会处理使用JS模 ...

  7. 【Python网络编程】多线程聊天软件程序

    课程设计的时候制作的多线程聊天软件程序 基于python3.4.3 import socket import pickle import threading import tkinter import ...

  8. CreateThread简单那多线程编程

    CreateThread简单那多线程编程 作者:vpoet mail:vpoet_sir@163.com 在进行多任务处理的时候我们往往会用到多线程技术,多线程理论上是多个线程同事处理不同的工作,但是 ...

  9. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

随机推荐

  1. js replace如何实现replaceAll

    js下string对象的replace方法的定义如下: stringObject.replace(regexp/substr,replacement) 其中: 参数             |     ...

  2. php 性能优化

    php 性能测试工具 ab(Apache Benchmark) ab 是由 Apache 提供的压力测试软件.安装 apache 服务器时会自带该压测软件. 如何使用: ab -n1000 -c100 ...

  3. 八、java常用类

    目录 一.字符串相关类 String类 StringBuffer类 二.基本数据类型包装类 三.Math类 四.File类 五.枚举类 一.字符串相关类 1.String类 java.lang.Str ...

  4. 六、java异常处理

    目录 一.异常的概念 二.异常的分类 三.异常的捕获和处理 四.使用自定义异常 一.异常的概念 java异常是指java提供的用于处理程序运行过程中错误的一种机制 所谓错误是指在程序运行的过程中发生的 ...

  5. Java入门:练习——自定义通用工具类

    请编写一个通用工具类,该类具有如下功能: 1)判断一个字符串是否是邮箱地址 2)判断一个字符串是否是手机号码 3)判断一个字符串是否是电话号码 4)判断一个字符串是否是IP地址 代码结构如下,请补充完 ...

  6. GoWeb_01:GoWeb基础之mac上mysql安装

    Mac下的MySql安装与配置 1. 访问MySQL的官网 http://www.mysql.com/downloads/ 然后在页面中会看到“MySQL Community Server”下方有一个 ...

  7. random函数详解

    1. 随机函数  Math.random() Math.random();    取值范围是  [ 0.0,1.0 )  的左闭右开区间.具体源代码如下所示:   Math.random()是生成0~ ...

  8. Python入门系列教程(三)列表和元组

    增 1.insert A = ['] A.insert(0,0) print A 2.append A = ['] A.append(7) print A 3.extend A = ['] B = [ ...

  9. asp.net后台操作javascript:confirm返回值

    在asp.net中使用confirm可以分为两种: 1.没有使用ajax,confirm会引起也面刷新 2.使用了ajax,不会刷新 A.没有使用ajax,可以用StringBuilder来完成. ( ...

  10. 简单理解 NP, P, NP-complete和NP-Hard

    P是一类可以通过确定性图灵机(以下简称 图灵机)在多项式时间(Polynomial time)内解决的问题集合. NP是一类可以通过非确定性图灵机( Non-deterministic Turing ...