TCP编写的聊天室

标题: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();
			}
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值