与自己写的对比后的体悟:在自学过程中,封装是比较难以把控的,好的封装技巧可以为程序开发带来巨大的便利。
客户端发送线程:
/**
* 使用多线程封装:发送端
* 1、发送消息
* 2、从控制台获取消息
* 3、释放资源
* 4、重写run
* @author 裴新 QQ:3401997271
*
*/
public class Send implements Runnable {
private BufferedReader console ;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name;
public Send(Socket client,String name) {
this.client =client;
console =new BufferedReader(new InputStreamReader(System.in));
this.isRunning = true;
this.name = name;
try {
dos =new DataOutputStream(client.getOutputStream());
//发送名称
send(name);
} catch (IOException e) {
System.out.println("==1==");
this.release();
}
}
@Override
public void run() {
while(isRunning) {
String msg = getStrFromConsole();
if(!msg.equals("")) {
send(msg);
}
}
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println(e);
System.out.println("===3==");
release();
}
}
/**
* 从控制台获取消息
* @return
*/
private String getStrFromConsole() {
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
//释放资源
private void release() {
this.isRunning = false;
SxtUtils.close(dos,client);
}
}
客户端接收功能:
/**
* 使用多线程封装:接收端
* 1、接收消息
* 2、释放资源
* 3、重写run
* @author 裴新 QQ:3401997271
*
*/
public class Receive implements Runnable {
private DataInputStream dis ;
private Socket client;
private boolean isRunning;
public Receive(Socket client) {
this.client = client;
this.isRunning = true;
try {
dis =new DataInputStream(client.getInputStream());
} catch (IOException e) {
System.out.println("====2=====");
release();
}
}
//接收消息
private String receive() {
String msg ="";
try {
msg =dis.readUTF();
} catch (IOException e) {
System.out.println("====4====");
release();
}
return msg;
}
@Override
public void run() {
while(isRunning) {
String msg =receive();
if(!msg.equals("")) {
System.out.println(msg);
}
}
}
//释放资源
private void release() {
this.isRunning = false;
SxtUtils.close(dis,client);
}
}
客户端:
/**
* 在线聊天室: 客户端
* 目标: 私聊
* @author 裴新 QQ:3401997271
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("-----Client-----");
BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String name =br.readLine();
//1、建立连接: 使用Socket创建客户端 +服务的地址和端口
Socket client =new Socket("localhost",8888);
//2、客户端发送消息
new Thread(new Send(client,name)).start();
new Thread(new Receive(client)).start();
}
}
服务端:
/**
* 在线聊天室: 服务器
* 目标: 私聊
* @author 裴新 QQ:3401997271
*
*/
public class Chat {
private static CopyOnWriteArrayList<Channel> all =new CopyOnWriteArrayList<Channel>();
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
// 1、指定端口 使用ServerSocket创建服务器
ServerSocket server =new ServerSocket(8888);
// 2、阻塞式等待连接 accept
while(true) {
Socket client =server.accept();
System.out.println("一个客户端建立了连接");
Channel c =new Channel(client);
all.add(c); //管理所有的成员
new Thread(c).start();
}
}
//一个客户代表一个Channel
static class Channel implements Runnable{
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name;
public Channel(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
dos =new DataOutputStream(client.getOutputStream());
isRunning =true;
//获取名称
this.name =receive();
//欢迎你的到来
this.send("欢迎你的到来");
sendOthers(this.name+"来了shsxt聊天室",true);
} catch (IOException e) {
System.out.println("---1------");
release();
}
}
//接收消息
private String receive() {
String msg ="";
try {
msg =dis.readUTF();
} catch (IOException e) {
System.out.println("---2------");
release();
}
return msg;
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println("---3------");
release();
}
}
/**
* 群聊:获取自己的消息,发给其他人
* 私聊: 约定数据格式: @xxx:msg
* @param msg
*/
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if(isPrivate) { //私聊
int idx =msg.indexOf(":");
//获取目标和数据
String targetName = msg.substring(1,idx);
msg = msg.substring(idx+1);
for(Channel other: all) {
if(other.name.equals(targetName)) {//目标
other.send(this.name +"悄悄地对您说:"+msg);
break;
}
}
}else {
for(Channel other: all) {
if(other==this) { //自己
continue;
}
if(!isSys) {
other.send(this.name +"对所有人说:"+msg);//群聊消息
}else {
other.send(msg); //系统消息
}
}
}
}
//释放资源
private void release() {
this.isRunning = false;
SxtUtils.close(dis,dos,client);
//退出
all.remove(this);
sendOthers(this.name+"离开大家庭...",true);
}
@Override
public void run() {
while(isRunning) {
String msg = receive() ;
if(!msg.equals("")) {
//send(msg);
sendOthers(msg,false);
}
}
}
}
}
工具类:
/**
* 工具类
*
* @author 裴新 QQ:3401997271
*
*/
public class SxtUtils {
/**
* 释放资源
*/
public static void close(Closeable... targets ) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
}
}
}
}