Send.java
作用:对传进去的Socket类型对象进行初始化操作,并可从控制台获取消息并通过服务器端发送到其他客户端。
package Test_Net;
import java.io.Closeable;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class Send implements Runnable {
private DataOutputStream dos ;
private Socket client;
boolean isrunning = false;
String name;
public Send(Socket client,String name){
isrunning = true;
this.name = name;
this.client = client;
try {
dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(name);
} catch (IOException e) {
free();
}
}
public void send(String message){
try {
dos.writeUTF(message);
dos.flush();
} catch (IOException e) {
free();
}
}
public String getInputString(){
Scanner input = new Scanner(System.in);
String message = input.next();
return message;
}
public void run() {
while (isrunning){
String message = getInputString();
if(!"".equals(message)){
send(message);
}
}
}
public void free(){
isrunning = false;
close(dos,client);
}
public static void close(Closeable... targets ) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
}
}
}
}
Receive.java
作用:对传进去的Socket类型对象进行初始化操作,并能将接收到的信息在控制台打印出来。
package Test_Net;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receive implements Runnable {
private DataInputStream dis = null;
private Socket client =null;
private boolean isrunning = false;
public Receive(Socket client){
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
} catch (IOException e) {
free();
}
isrunning = true;
}
public String receice(){
String message = "";
try {
message = dis.readUTF();
} catch (IOException e) {
free();
}
return message;
}
public void run() {
while (isrunning){
String message = receice();
if(!"".equals(message)){
System.out.println(message);
}
}
}
public void free(){
isrunning = false;
close(dis,client);
}
public static void close(Closeable... targets ) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
}
}
}
}
costomer.java
作用:针对于服务器端的描述客户端的类,对每一个客户端的初始化以及实现客户端之间进行群聊或私聊功能。
群聊功能很容易实现,只需要将消息遍历costomer容器发送至每一个客户端即可,而私聊功能则需要规定
私聊的语言规范 在这里我的规范是以@开头 再加要发送给对应的客户端的姓名再加上冒号 后边才是消息内容
eg: @zmj:快叫哥哥
有了这个规范,只需要对传输过来的字符串进行简单的判断和截取,就可以成功解析出对象的name属性以及
要发送的内容,在容器中遍历查找即可得到对应的接收端对象,从而实现私聊。
package Test_Net;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
public class costomer implements Runnable {
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean isrunning;
private String name;
CopyOnWriteArrayList<costomer> all;
public costomer(Socket client,CopyOnWriteArrayList<costomer> all ) {
this.all = all;
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) {
release();
}
}
//接收消息
private String receive() {
String msg ="";
try {
msg =dis.readUTF();
} catch (IOException e) {
release();
}
return msg;
}
//发送消息
private void send(String msg) {
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
release();
}
}
/**
* 私聊规范:
*
* @+name+:+内容
*/
private void sendOthers(String msg,boolean isallbody) {
boolean isone = false;
isone = msg.startsWith("@");
if(!isone) {
for (costomer other : all) {
if (other == this) { //自己
continue;
}
if (isallbody) {
other.send(this.name + "对所有人说:" + msg);//群聊消息
} else {
other.send(msg); //系统消息
}
}
}
else {
String name= msg.substring(msg.indexOf('@')+1,msg.indexOf(':'));
String infor = msg.substring(msg.indexOf(':')+1);
for(costomer t:all){
if(name.equals(t.name)){
t.send(this.name+" (悄悄对你说):"+infor);
}
}
}
}
//释放资源
private void release() {
this.isrunning = false;
free();
all.remove(this);
sendOthers(this.name+"离开...",false);
}
public void free(){
isrunning = false;
close(dis,dos,client);
}
public static void close(Closeable... targets ) {
for(Closeable target:targets) {
try {
if(null!=target) {
target.close();
}
}catch(Exception e) {
}
}
}
@Override
public void run() {
while(isrunning) {
String msg = receive() ;
if(!msg.equals("")) {
//send(msg);
sendOthers(msg,true);
}
}
}
}
TestChat.java
作用:实际的客户端程序,可多次运行建立多个客户端连接,实现多人聊天。
其中加入多线程,可使接收消息和发送消息并发执行,更贴合实际的多人聊天。
package Test_Net;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class TestChat {
public static void main(String[] args) throws IOException {
System.out.println("-*-------客户端-------*-");
System.out.println("输入用户名");
Scanner input = new Scanner(System.in);
Socket client = new Socket("localhost",6667);
String name = input.next();
new Thread(new Send(client,name)).start();
new Thread(new Receive(client)).start();
}
}
TestServerchat.java
作用:实际的服务器端程序,创建服务器,并循环阻塞式与客户端建立连接,并将所有建立连接的客户端存储至容器中,便于对群聊私聊进行操作。
package Test_Net;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;
public class TestServerchat {
public static void main(String[] args) throws IOException {
System.out.println("------------服务器端-------------");
ServerSocket server = new ServerSocket(6667);
CopyOnWriteArrayList<costomer> all = new CopyOnWriteArrayList<costomer>();
while (true){
Socket client = server.accept();
System.out.println("一个客户端建立了连接..");
costomer c = new costomer(client,all);
all.add(c);
new Thread(c).start();
}
}
}
总结:基于TCP编程的小型多人聊天室,加深了对多线程,以及输入输出流、网络编程的理解。是个很好的练习项目。