java Socket实现简单在线聊天(三)
在上一篇,利用线程使服务端实现了能够接收多客户端请求的功能,这里便需要客户端接收多客户端消息的同时还能把消息转发到每个连接的客户端,并且客户端要能在内容显示区域显示出来,从而实现简单的在线群聊。
package chat.chat;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Random;
/**
* 在线聊天客户端 步骤: 1、生成图形窗口界面轮廓 2、为轮廓添加关闭事件 3、在轮廓中加入输入区域和内容展示区域 4、为输入区域添加回车事件
* 5、建立服务端连接并发送数据
*
* @author tuzongxun123
*
*/
public class ChatClient extends Frame {
/**
*
*/
private static final long serialVersionUID = 1L;
// 用户输入区域
private TextField tfTxt = new TextField();
// 内容展示区域
private TextArea tarea = new TextArea();
private Socket socket = null;
// 数据输出流
private DataOutputStream dataOutputStream = null;
// 数据输入流
private DataInputStream dataInputStream = null;
private boolean isConnect = false;
Thread tReceive = new Thread(new ReceiveThread());
String name = "";
public static void main(String[] args) {
ChatClient chatClient = new ChatClient();
chatClient.createName();
chatClient.launcFrame();
}
/**
* 建立一个简单的图形化窗口
*
* @author:tuzongxun
* @Title: launcFrame
* @param
* @return void
* @date May 18, 2016 9:57:00 AM
* @throws
*/
public void launcFrame() {
setLocation(300, 200);
this.setSize(200, 400);
add(tfTxt, BorderLayout.SOUTH);
add(tarea, BorderLayout.NORTH);
// 根据窗口里面的布局及组件的preferedSize来确定frame的最佳大小
pack();
// 监听图形界面窗口的关闭事件
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
disConnect();
}
});
tfTxt.addActionListener(new TFLister());
// 设置窗口可见
setVisible(true);
connect();
// 启动接受消息的线程
tReceive.start();
}
/**
* 连接服务器
*
* @author:tuzongxun
* @Title: connect
* @param
* @return void
* @date May 18, 2016 9:56:49 AM
* @throws
*/
public void connect() {
try {
// 新建服务端连接
socket = new Socket("127.0.0.1", 8888);
// 获取客户端输出流
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataInputStream = new DataInputStream(socket.getInputStream());
System.out.println("连上服务端");
isConnect = true;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// 生成随机的客户端名字
public void createName() {
String[] str1 = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "0", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z" };
Random ran = new Random();
for (int i = 0; i < 6; i++) {
// long num = Math.round(Math.random() * (str1.length - 0) + 0);
// int n = (int) num;
int n = ran.nextInt(str1.length);
if (n < str1.length) {
String str = str1[n];
name = name + str;
System.out.println(name);
} else {
i--;
continue;
}
}
this.setTitle(name);
}
/**
* 关闭客户端资源
*
* @author:tuzongxun
* @Title: disConnect
* @param
* @return void
* @date May 18, 2016 9:57:46 AM
* @throws
*/
public void disConnect() {
try {
isConnect = false;
// 停止线程
tReceive.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
if (dataOutputStream != null) {
dataOutputStream.close();
}
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 向服务端发送消息
*
* @author:tuzongxun
* @Title: sendMessage
* @param @param text
* @return void
* @date May 18, 2016 9:57:56 AM
* @throws
*/
private void sendMessage(String text) {
try {
dataOutputStream.writeUTF(name + ":" + text);
dataOutputStream.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
}
/**
* 图形窗口输入区域监听回车事件
*
* @author tuzongxun123
*
*/
private class TFLister implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String text = tfTxt.getText().trim();
// 清空输入区域信息
tfTxt.setText("");
// 回车后发送数据到服务器
sendMessage(text);
}
}
private class ReceiveThread implements Runnable {
@Override
public void run() {
try {
while (isConnect) {
String message = dataInputStream.readUTF();
System.out.println(message);
String txt = tarea.getText();
if (txt != null && !"".equals(txt.trim())) {
message = tarea.getText() + "\n" + message;
}
tarea.setText(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package chat.chat;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
/**
* java使用socket和awt组件以及多线程简单实现在线聊天功能服务端 :
* 实现服务端把接收到的客户端信息转发到所有连接的客户端,并且让客户端读取到这些信息并显示在内容显示区域中。
*
* @author tuzongxun123
*
*/
public class ChatServer {
public static void main(String[] args) {
new ChatServer().start();
}
// 是否成功启动服务端
private boolean isStart = false;
// 服务端socket
private ServerSocket ss = null;
// 客户端socket
private Socket socket = null;
// 保存客户端集合
List<Client> clients = new ArrayList<Client>();
public void start() {
try {
// 启动服务器
ss = new ServerSocket(8888);
} catch (BindException e) {
System.out.println("端口已在使用中");
// 关闭程序
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
try {
isStart = true;
while (isStart) {
// 启动监听
socket = ss.accept();
System.out.println("one client connect");
// 启动客户端线程
Client client = new Client(socket);
new Thread(client).start();
clients.add(client);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭服务
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端线程
*
* @author tuzongxun123
*
*/
private class Client implements Runnable {
// 客户端socket
private Socket socket = null;
// 客户端输入流
private DataInputStream dataInputStream = null;
// 客户端输出流
private DataOutputStream dataOutputStream = null;
private boolean isConnect = false;
public Client(Socket socket) {
this.socket = socket;
try {
isConnect = true;
// 获取客户端输入流
dataInputStream = new DataInputStream(socket.getInputStream());
// 获取客户端输出流
dataOutputStream = new DataOutputStream(
socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 向客户端群发(转发)数据
*
* @author:tuzongxun
* @Title: sendMessageToClients
* @param @param message
* @return void
* @date May 18, 2016 11:28:10 AM
* @throws
*/
public void sendMessageToClients(String message) {
try {
dataOutputStream.writeUTF(message);
} catch (SocketException e) {
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
isConnect = true;
Client c = null;
try {
while (isConnect) {
// 读取客户端传递的数据
String message = dataInputStream.readUTF();
System.out.println("客户端说:" + message);
for (int i = 0; i < clients.size(); i++) {
c = clients.get(i);
c.sendMessageToClients(message);
}
}
} catch (EOFException e) {
System.out.println("client closed!");
} catch (SocketException e) {
if (c != null) {
clients.remove(c);
}
System.out.println("Client is Closed!!!!");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭相关资源
try {
if (dataInputStream != null) {
dataInputStream.close();
}
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
java Socket实现简单在线聊天(三)的更多相关文章
- java Socket实现简单在线聊天(二)
接<java Socket实现简单在线聊天(一)>,在单客户端连接的基础上,这里第二步需要实现多客户端的连接,也就需要使用到线程.每当有一个新的客户端连接上来,服务端便需要新启动一个线程进 ...
- java Socket实现简单在线聊天(一)
最近的项目有一个在线网页交流的需求,由于很久以前做过的demo已经忘记的差不多了,因此便重新学习一下. 我计划的大致实现步骤分这样几大步: 1.使用awt组件和socket实现简单的单客户端向服务端持 ...
- vue实现简单在线聊天
vue实现简单在线聊天 引用mui的ui库,ES6的 fetch做网络请求 //html <!DOCTYPE html> <html> <head> <met ...
- AngularJS+Node.js+socket.io 开发在线聊天室
所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...
- 基于Server-Sent Event的简单在线聊天室
Web即时通信 所谓Web即时通信,就是说我们可以通过一种机制在网页上立即通知用户一件事情的发生,是不需要用户刷新网页的.Web即时通信的用途有很多,比如实时聊天,即时推送等.如当我们在登陆浏览知乎时 ...
- Socket实现简单的聊天通信
最近学习了Socket后,感觉Socket挺好玩的,在博客中看到socket在实时聊天功能的很强大,于是乎就做了一个简单的聊天功能,今天贴出来,能够与大家一起共享,有不对之处,能够给予指出,谢谢! 服 ...
- WinForm的Socket实现简单的聊天室 IM
1:什么是Socket 所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象. 一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制. 从 ...
- java socket之多人聊天室Demo
一.功能介绍 该功能实现了一个类似QQ的最简单多人聊天室,如下图所示. 二.目录结构 三.服务端 1)SocketServer类,该类是服务端的主类,主要负责创建聊天窗口,创建监听客户端的线程: pa ...
- JAVA Socket基础(简单实现)
学习Socket需要了解的几个概念: Socket 指的是互联网连接中的各个终结点.互联网连接是怎么创建的,通过IP地址加端口号,进行互通. A电脑(192.168.3.125:80)>> ...
随机推荐
- Django中不返回QuerySets的API -- Django从入门到精通系列教程
该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. Python及Django学习QQ群:453 ...
- Storm 对 0.10.x 版 Kafka之commit offsets
由于 0.10.x 版 Kafka 与 0.8.x 版有很大的变化,这种变化对下游 Storm 有非常大的影响,0.10.x 版的 Kafka 不但增加了权限管理的功能,而且还将 simple 和 h ...
- HTML核心标签之表格标签(一)
表格的基本语法: <body> <table> <tr><td></td><td></td></tr> ...
- 使用TensorFlow Object Detection API+Google ML Engine训练自己的手掌识别器
上次使用Google ML Engine跑了一下TensorFlow Object Detection API中的Quick Start(http://www.cnblogs.com/take-fet ...
- python学习交流 - 匿名函数
匿名函数 匿名函数是一个很有特色的定义函数的功能.在实际使用的过程,用户有时不得不为一些一行代码即可实现的功能来定义一个函数,例如像map, max, filter等内置函数的key参数只能接收可调用 ...
- 为MySQL选择合适的备份方式[转]
原文链接:http://nettedfish.sinaapp.com/blog/2013/05/31/choose-suitable-backup-strategy-for-mysql/ 数据库的备份 ...
- CF798E. Mike and code of a permutation [拓扑排序 线段树]
CF798E. Mike and code of a permutation 题意: 排列p,编码了一个序列a.对于每个i,找到第一个\(p_j > p_i\)并且未被标记的j,标记这个j并\( ...
- c语言中的register int
register int a=1; 明确声明必须要把变量存放在寄存器中,直到变量消失. 一般是默认register,大多数的情况下是不用写register
- Redis进阶实践之十 Redis哨兵集群模式
一.引言 上一篇文章我们详细的讲解了Redis的主从集群模式,其实这个集群模式配置很简单,只需要在Slave的节点上进行配置,Master主节点的配置不需要做任何更改,但是有一 ...
- 重写equals()和hashCode()
什么时候需要重写equals()? 只有当一个实例等于它本身的时候,equals()才会返回true值.通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相 等.而我们在使用 ...