tcp 通过控制台模拟在线聊天
客户端
package cn.com.Inet3;
import java.io.*;
import java.net.Socket;
public class Client2 {
public static void main(String[] args) throws IOException {
//使用多线程实现多个客户可以正常收发多条消息
System.out.println("------client-------");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String name = br.readLine();
Socket client = new Socket("localhost",6666);
//客户端发送消息
new Thread(new Send(client,name)).start();
new Thread(new Receive(client)).start();
}
}
package cn.com.Inet3;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
//发送端 使用了多线程封装了发送端
// 发送消息 从控制台获取消息 释放资源 重写run
public class Send implements Runnable{
private Socket client;
private BufferedReader console;
private DataOutputStream dos;
private boolean isRunning;
private String name;
public Send(Socket client,String name) {
this.client = client;
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
//管道建立好了 立即发送名称 在线程启动前将名称发过来
send(name);
this.isRunning = true;
this.name = 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("=====3====");
this.release();
}
}
//从控制台获取消息
private String getStrFromConsole() {
try {
return console.readLine();
} catch (IOException e) {
System.out.println("=====2====");
this.release();
}
return null;
}
private void release() {
this.isRunning = false;
Utiles.close(client,dos);
}
}
package cn.com.Inet3;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
//接收端 使用多线程封装了接收端
//接受消息 释放资源 重写run
public class Receive implements Runnable{
private Socket client;
private DataInputStream dis;
private boolean isRunning;
public Receive(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
isRunning = true;
} catch (IOException e) {
System.out.println("*******1********");
this.release();
}
}
@Override
public void run() {
while(isRunning) {
String msg = receive();
if (!msg.equals("")) {
System.out.println(msg);
}
}
}
private String receive() {
try {
String msg = dis.readUTF();
return msg;
} catch (IOException e) {
System.out.println("*******3********");
this.release();
}
return null;
}
private void release() {
this.isRunning = false;
Utiles.close(dis,client);
}
}
服务器端
package cn.com.Inet3;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
public class Chat2 {
private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>();
//加入容器实现群聊
public static void main(String[] args) throws IOException {
//使用多线程实现多个客户可以正常收发多条消息
//问题 其它客户必须等待之前的客户退出,才能继续 排队 加入多线程解决问题
//问题 代码不好维护 客户端读写没有分开 必须先写后读
System.out.println("-----server-----");
ServerSocket server = new ServerSocket(6666);
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 Socket client;
private DataInputStream dis;
private DataOutputStream dos;
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+"来到了余小浩的聊天室",true);
} catch (IOException e) {
System.out.println("-----1-----");
release();
}
}
//接收消息
private String receive() {
try {
String msg = dis.readUTF();
return msg;
} catch (IOException e) {
System.out.println("-----2-----");
release();
}
return null;
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
System.out.println("-----3-----");
release();
}
}
//群聊
//私聊 约定数据格式@xxx:msg
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if (isPrivate) {//私聊
int index = msg.indexOf(":");
//获取目标和数据
String targetName = msg.substring(1,index);
msg = msg.substring(index+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;
Utiles.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);//发给其他人
}
}
}
}
}
工具类
package cn.com.Inet3;
import java.io.Closeable;
public class Utiles {
//释放资源
public static void close(Closeable...targets) {
for (Closeable target:targets) {
try {
if (target != null) {
target.close();
}
}catch(Exception e) {
}
}
}
}