基于TCP协议的聊天室控制台版
我之前写过一篇博客,主要是基于TCP协议实现的聊天室swing版,在此再写一个基于TCP协议实现的聊天室控制台版,便于学习和比较。
package 聊天室console版.utils;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 工具类,服务器端的有关信息
* @author 李章勇
*
*/
public abstract class HostInfo {
//访问权限,供不同包访问
public static String ip=getIp();
public static final int port=10086;
public static final int num=50;
private static String getIp(){
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
return null;
}
}
}
-------------------------------------------------------
package 聊天室console版.utils;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 工具类,释放资源
* @author 李章勇
*
*/
public abstract class Release {
//访问权限,public,可以供不同包的对象访问
public static void release(Socket socket,BufferedWriter bw){
release(null,socket,null,bw);
}
public static void release(Socket socket,BufferedReader br){
release(null,socket,br,null);
}
public static void release(Socket socket){
release(null,socket,null,null);
}
public static void release(ServerSocket server){
release(server,null,null,null);
}
public static void release(ServerSocket server,Socket socket,BufferedReader br,BufferedWriter bw){
if(server!=null){
try {
server.close();
} catch (IOException e) {
System.err.println("服务器创建失败!");
}
}
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
System.err.println("客户端创建失败!");
}
}
if(br!=null){
try {
br.close();
} catch (IOException e) {
System.err.println("输入流创建失败!");
}
}
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
System.err.println("输出流创建失败!");
}
}
}
}
--------------------------------------------------------------------
package 聊天室console版.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import 聊天室console版.utils.HostInfo;
import 聊天室console版.utils.Release;
/**
* 服务器端类
* 要先开启服务器,再开启客户端
* @author 李章勇
*
*/
public class Server {
//仅可以在同一包内访问 涉及查询和增删 用ArrayList集合
static List<Transport> clients=new ArrayList<>();
//服务器构造器
public Server(){
//创建服务器套接字,工具类中的属性
ServerSocket server=null;
try {
server=new ServerSocket(HostInfo.port);
} catch (IOException e) {
Release.release(server);
throw new RuntimeException("服务器端口被占!启动服务器失败!");
}
System.out.println("服务器开启成功!");
//接收来自客户端的连接请求,最多接收50个
int num=0;
Socket socket=null;
while(num<HostInfo.num){
try {
socket=server.accept();
} catch (IOException e) {
//释放资源,结束本次循环,进行下一轮循环
Release.release(socket);
continue;
}
System.out.println("第 "+(++num)+" 个客户端成功接入!=="
+socket.getInetAddress().getHostAddress()
+":"+socket.getPort());
//另起一个子线程,专门处理与客户端的数据交互,同时传递入该socket对象 Transport
//并将该转发类对象存入一个集合对象
clients.add(new Transport(socket));
}
System.err.println("超出服务器负荷!");
Release.release(server);
}
//服务器主线程
public static void main(String[] args) {
new Server();
}
}
-------------------------------------------------
package 聊天室console版.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import 聊天室console版.utils.Release;
/**
* 服务器端,处理信息(客户端发来的,以及给客户端转发的)
* @author 李章勇
*
*/
public class Transport extends Thread {
//访问权限 仅供本类对象使用
private Socket socket;
private String ip;
public Transport(Socket socket){
this.socket=socket;
this.ip=socket.getInetAddress().getHostAddress();
this.start();
}
@Override
public void run() {
//从客户端获取流
BufferedReader br=null;
BufferedWriter ownbw=null;
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
ownbw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
} catch (IOException e) {
Server.clients.remove(this);
Release.release(socket, br);
throw new RuntimeException("获取流失败!");
}
//从客户端流中循环读数据
String str=null;
try {
while((str=br.readLine())!=null){
String[] split = str.split(":", 2);
if(split.length<=1){
ownbw.write("您发送的数据格式有误,请重新发送!");
ownbw.newLine();
ownbw.flush();
}else{
String desip=split[0];
String content=split[1];
//判断对方是否在线,准备给给目标转发信息
BufferedWriter desbw=null;
boolean isOnLine=false;
for(Transport des:Server.clients){
if(desip.equals(des.ip)){
isOnLine=true;
desbw=new BufferedWriter(new OutputStreamWriter(des.socket.getOutputStream()));
desbw.write(ip+" -->对你说:"+content);
desbw.newLine();
desbw.flush();
}
}
if(!isOnLine){
ownbw.write("对方 "+desip+"不在线!");
ownbw.newLine();
ownbw.flush();
}
}
}
} catch (IOException e) {
Server.clients.remove(this);
Release.release(socket, br);
throw new RuntimeException("获取流失败!");
}
}
}
-----------------------------------------------------------
package 聊天室console版.client;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import 聊天室console版.utils.HostInfo;
import 聊天室console版.utils.Release;
/**
* 客户端类
* @author 李章勇
*
*/
public class Client {
private Socket socket=null;
public Client(){
//向服务器发起连接请求
try {
socket=new Socket(HostInfo.ip, HostInfo.port);
}catch (IOException e) {
Release.release(socket);
throw new RuntimeException("客户端创建失败!");
}
//另建一个子线程从服务器循环读取数据
new Receive().start();
//向服务器循环写流
BufferedWriter bw=null;
Scanner sc=new Scanner(System.in);
String str=null;
try {
bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(true){
System.out.println("请发送数据(格式-->对方ip:信息内容):");
str=sc.nextLine();
bw.write(str);
bw.newLine();
bw.flush();
}
} catch (IOException e) {
Release.release(socket, bw);
throw new RuntimeException("向服务器写流失败!");
}
}
private class Receive extends Thread{
@Override
public void run() {
BufferedReader br=null;
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
Release.release(socket, br);
throw new RuntimeException("从服务器获取流失败!");
}
String str=null;
//从服务器循环获取流
try {
while((str=br.readLine()) != null){
System.out.println(str);
}
} catch (IOException e) {
Release.release(socket, br);
throw new RuntimeException("从服务器获取流失败!");
}
}
}
public static void main(String[] args) {
new Client();
}
}