标题:TCP编写的聊天室
一、服务器端编程步骤:
- 1.创建ServerSocket(int port)对象
- 2.在Socket上监听客户端的连接请求
- 3.阻塞、等待连接的建立
- 4.接收并处理请求信息
- 5.将处理结果返回给客户端
- 6.关闭流和Socket对象
二、客户端编程步骤:
- 1.创建Socket(String host,int port)对象
- 2.向服务器发送连接请求
- 3.向服务器发送服务请求
- 4.接收服务结果
- 5.关闭流和Socket对象
三、实现通信
原理:多个客户端将消息发送个服务器,服务器接收后反馈给客户端
1)第一步,首先服务器端,客户端建立连接
2)第二步,客户端发送消息给服务器端,服务器端反馈客户端的消息
3)第三步,服务器端需使用while循环实现建立多次连接,从而可以实现多个客户端与一个服务器端通信,注意:此处需使用多线程,否则实现不了多个客户端与服务器端的同时通信
while(flag) {
//2.在Socket上监听客户端的连接请求
client=server.accept();
//3.阻塞、等待连接的建立
System.out.println("建立好了一次连接"); //这样写必须等第一个客户端建立好了连接,发送了账号、密码,才能接收其他的客户端
//使用线程的原因,是因为可以不用等待线程体中的代码运行完,再次接收客户端的请求
new Thread(new Channel(client,list)).start();
}
4)可以不要。在服务器的多线程中测试输入的账号密码正确与否,正确就开启通信,错误则关闭客户端。若此判断未在多线程里面,则实现不了客户端的同时登入
5)实现客户端接收消息,与发送消息的同时性,分别使用多线程,是的可以同时接收,发送消息。
服务器端完整代码如下:
//实现client发送账号、密码,server给出匹配成功or失败,成功则接收客户端的消息,失败则关闭客户端
//增加了界面友好型,以及多个用户
//封装版
/**
* 1.创建ServerSocket(int port)对象
* 2.在Socket上监听客户端的连接请求
* 3.阻塞、等待连接的建立
* 4.接收并处理请求信息
* 5.将处理结果返回给客户端
* 6.关闭流和Socket对象
* @author dell
*
*/
public class TestChatServer03 {
public static void main(String[] args) throws IOException {
System.out.println("-----Server-----");
//1.创建ServerSocket(int port)对象
ServerSocket server=new ServerSocket(6666);
Socket client=null;
// ArrayList<OutputStream> list=new ArrayList<>();
CopyOnWriteArrayList<OutputStream> list=new CopyOnWriteArrayList<>();
boolean flag=true;
while(flag) {
//2.在Socket上监听客户端的连接请求
client=server.accept();
//3.阻塞、等待连接的建立
System.out.println("建立好了一次连接"); //这样写必须等第一个客户端建立好了连接,发送了账号、密码,才能接收其他的客户端
//使用线程的原因,是因为可以不用等待线程体中的代码运行完,再次接收客户端的请求
new Thread(new Channel(client,list)).start();
}
server.close();
}
static class Channel implements Runnable{
private Socket client;
private DataInputStream is;
private DataOutputStream os;
String trueName="lkj";
String truePassWord="123";
String name="";
String passWord="";
CopyOnWriteArrayList<OutputStream> list;
public Channel(Socket client,CopyOnWriteArrayList<OutputStream> list) {
this.list=list;
this.client = client;
try {
//从流中读取消息,【接收客户端的消息】
this.is =new DataInputStream(client.getInputStream());
//写到到消息到流中,【发送消息到客户端】
this.os =new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
};
}
@Override
public void run() {
//4.接收并处理请求信息
//先接受账号,密码信息,匹配成功,读取client的其它信息,失败,则关闭client
String str="";
try {
//从流中读取消息,【接收客户端的消息】
str=is.readUTF();
//分割str得到name,passWord
this.splitStr(str);
//匹配成功
if((trueName.equals(name)&&truePassWord.equals(passWord))
||(name.equals("aaa")&&passWord.equals("123"))
||(name.equals("bbb")&&passWord.equals("123")))
{
os.writeUTF("欢迎回来主人!!!");
System.out.println("客户端登入成功!!!");
list.add(client.getOutputStream());
for(OutputStream oos:list) {
if(oos!=client.getOutputStream()) {
this.writeU(name+"进入了群聊!!!", oos);
}
}
//从client读取的内容,反馈输出,通信
this.comWithClient();
list.remove(client.getOutputStream());
}else {
//匹配失败
os.writeUTF("用户名或密码不正确");
System.out.println("客户端登入失败,可能是用户名或密码不正确");
}
} catch (IOException e) {
e.printStackTrace();
}
//6.关闭流和Socket对象
System.out.println("接收完毕!!!");
// this.free();
}
private String readU() {
try {
return is.readUTF();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private void writeU(String str,OutputStream os) {
try {
new DataOutputStream(os).writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
}
//分割str得到name,passWord
private void splitStr(String str) {
if(str.indexOf("&")!=-1) {//str.contains("&")
String[] s=str.split("&");
for(String s2:s) {
if(s2.split("=")[0].equals("name")) {
name=s2.split("=")[1];
}else if(s2.split("=")[0].equals("passWord")) {
passWord=s2.split("=")[1];
}
}
}
}
//从client读取的内容,反馈输出
private void comWithClient() throws IOException {
//读取客户端的内容,并输出至客户端
String str="";
while(!str.equals("exit")) {//因为客户端使用的是BufferedReader 丢弃了\r\n,方便,可以直接判断,否则是,length()-2
str=this.readU();
//5.将处理结果返回给客户端
if(list.size()<=1) {
this.writeU("当前群聊只有你自己,"+name+"对自己说:-->"+str,client.getOutputStream());
}else {
for(OutputStream oos:list) {
if(oos!=client.getOutputStream()) {
this.writeU(name+"对大家说:"+str, oos);
}
}
}
}
}
private void free() {
try {
if(null!=os) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
try {
if(null!=client) {
client.close();
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
客户端完整代码如下:
//实现client发送账号、密码,server给出匹配成功or失败,成功则接收客户端的消息,失败则关闭客户端
//增加了界面友好型,以及多个用户
/**
* 1.创建Socket(String host,int port)对象
* 2.向服务器发送连接请求
* 3.向服务器发送服务请求
* 4.接收服务结果
* 5.关闭流和Socket对象
* @author dell
*
*/
public class TestChatClient03 {
public static void main(String[] args) throws IOException {
System.out.println("-----Client-----");
//1.创建Socket(String host,int port)对象
//2.向服务器发送连接请求
Socket client=new Socket("localhost",6666);
//3.向服务器发送服务请求
//从输入流中读取消息,发送到流【服务器】中
BufferedReader is=new BufferedReader(new InputStreamReader(System.in));
DataOutputStream os=new DataOutputStream(client.getOutputStream());
System.out.print("输入账户名:");
String name=is.readLine();
System.out.print("输入密码:");
String passWord=is.readLine();
os.writeUTF("name="+name+"&"+"passWord="+passWord);
os.flush();
//从流中读取消息【从服务器读取】
DataInputStream dis=new DataInputStream(client.getInputStream());
String str=dis.readUTF();
System.out.println("客户端反馈的内容为-->"+str);
if(str.equals("欢迎回来主人!!!")) {
System.out.println("开始发送消息啦!!!");
new Thread(new Sended(client)).start();
new Thread(new Getted(client)).start();
}else {
System.out.println("登入失败,自动关闭客户端");
}
//5.关闭流和Socket对象
// client.close();
}
static class Sended implements Runnable{
private Socket client;
private BufferedReader is;
private DataOutputStream os;
public Sended(Socket client) {
super();
this.client = client;
try {
is=new BufferedReader(new InputStreamReader(System.in));
os=new DataOutputStream(client.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
String str="";
while(!str.equals("exit")) {
try {
str=is.readLine();
os.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
}
// this.free();
}
private void free() {
try {
if(null!=os) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
// try {
// if(null!=client) {
// client.close();
// }
// }catch(IOException e) {
// e.printStackTrace();
// }
}
}
static class Getted implements Runnable{
private Socket client;
private DataInputStream is;
public Getted(Socket client) {
super();
this.client = client;
try {
is=new DataInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
String str="";
while(!str.equals("exit")) {
try {
str=is.readUTF();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
}
// this.free();
}
private void free() {
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}