Socket编写简易聊天室

总体思路:多个客户端和服务端建立连接,客户端之间通过服务端做中转站传输数据

 

服务端

package com.ck.chat;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class Server {
	//用于存储对应用户的chat对象
	private Map<String,Chat> chats = new HashMap<String,Chat>();
	
	public Server() throws IOException {
		// 创建服务器并指定端口
		ServerSocket server = new ServerSocket(8888);

		while (true) {
			// 接收请求
			Socket client = server.accept();
			System.out.println("一个客户端建立连接,ip地址:" + client.getInetAddress() + "  端口:" + client.getPort());
			//生成聊天对象
			new Thread(){
				public void run(){
					try {
						DataInputStream dis = new DataInputStream(client.getInputStream());
						//接收用户的名字
						String name = dis.readUTF();
						//判断用户是否已存在
						Chat hasChat = chats.get(name);
						Chat chat = new Chat(Server.this,client,name);
						if(hasChat == null){
							System.out.println("用户(" + name + ")成功登录");
							chats.put(name, chat);
						}else{
							chat.sendToClient("你已登录");
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}.start();

		}
	}

	public static void main(String[] args) {
		try {
			new Server();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 服务器转发消息
	 * @param recvName 接收者名字
	 * @param message 消息内容
	 * @throws IOException 
	 */
	public void send(String recvName, String message) throws IOException {
		//得到接受者的聊天对象
		Chat chat = chats.get(recvName);
		//调用chat的发送消息方法
		chat.sendToClient(message);
	}

}

 

客户端

package com.ck.chat;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

	public Client() {
		DataOutputStream dos = null;
		try {
			// 指定服务器地址+端口
			Socket client = new Socket("localhost", 8888);

			System.out.print("请输入用户名:");
			BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
			dos = new DataOutputStream(client.getOutputStream());
			dos.writeUTF(getMsgFromConsole(console));
			dos.flush();
			
			new Chat(null,client,null);
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
			CloseUtil.closeAll(dos);
		} catch (IOException e) {
			e.printStackTrace();
			CloseUtil.closeAll(dos);
		}
	}

	public static void main(String[] args) throws UnknownHostException, IOException {
		new Client();
	}

	private String getMsgFromConsole(BufferedReader console) {
		try {
			return console.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}
}

 

Chat对象

package com.ck.chat;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 * 聊天对象,用于实现数据的发送和接收
 * @author sansheng__
 *
 */
public class Chat {

	private boolean clientIsRuning = true;
	private boolean serverIsRuning = true;
	private DataOutputStream dos;

	public Chat(Server server, Socket socket, String sendName) throws IOException {

		final DataInputStream dis = new DataInputStream(socket.getInputStream());
		final DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
		final BufferedReader console = new BufferedReader(new InputStreamReader(System.in));

		this.dos = dos;

		/**
		 * 客户端
		 */
		if (server == null) {
			
			/**
			 * 接收消息
			 */
			new Thread() {
				public void run() {
					while (clientIsRuning) {
						try {
							String msg = dis.readUTF();
							System.out.println(msg);
							if("你已登录".equals(msg)){
								socket.close();
							}
						} catch (Exception e) {
							e.printStackTrace();
							clientIsRuning = false;
							CloseUtil.closeAll(dis);
						}
					}
				}
			}.start();
			
			
			/**
			 * 发送消息
			 */
			new Thread() {
				public void run() {
					while (clientIsRuning) {
						try {
							// 读取客户端发送的消息
							String msg = console.readLine();
							// 输入byebye结束连接
							if ("byebye".equalsIgnoreCase(msg)) {
								socket.close();
								clientIsRuning = false;
							}
							if (msg != null && !"".equals(msg)) {
								dos.writeUTF(msg);
								dos.flush();
							}
						} catch (IOException e) {
							e.printStackTrace();
							clientIsRuning = false;
							CloseUtil.closeAll(dos);
						}
					}
				}
			}.start();
		}

		/**
		 * 服务端-接收消息
		 */
		if (server != null) {
			new Thread() {
				public void run() {
					while (serverIsRuning) {
						try {
							String msg = dis.readUTF();
							// System.out.println("客户端消息:" + msg);
							int index1 = msg.indexOf(":");
							int index2 = msg.indexOf(",");
							if (index1 < 0) {
								// 没有消息 服务器不转发
								System.out.println(msg);
							} else {
								// 有消息 服务器转发消息给对应的客户端
								if (index2 < 0) {
									// 私聊 xxx:你好
									String recvName = msg.substring(0, index1);
									String message = msg.substring(index1 + 1);
									// 服务器发消息
									server.send(recvName, sendName + "对你说:" + message);
								} else {
									// 群聊 xxx,xxx,xxx:你好
									String[] recvNames = msg.substring(0, index1).split(",");
									String message = msg.substring(index1 + 1);
									for (String name : recvNames) {
										server.send(name, sendName + "对你们说:" + message);
									}
								}
							}
						} catch (IOException e) {
							e.printStackTrace();
							serverIsRuning = false;
							CloseUtil.closeAll(dis);
						}
					}
				}
			}.start();
		}

	}

	/**
	 * 服务器给客户端发送消息
	 * 
	 * @param message
	 * @throws IOException
	 */
	public void sendToClient(String message) throws IOException {
		dos.writeUTF(message);
		dos.flush();
	}

}

 

CloseUtil

package com.ck.chat;

import java.io.Closeable;
import java.io.IOException;
/**
 * 关流工具类
 * @author sansheng__
 *
 */
public class CloseUtil {
	
	public static void closeAll(Closeable... ios) {
		for(Closeable temp : ios){
			if(temp != null){
				try {
					temp.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
里面包含聊天室的客户端和服务器端的源文件和一份完整的设计报告。 一、 系统概要 本系统能实现基于VC++的网络聊天室系统。有单独的客户端、服务器端。 服务器应用程序能够接受来自客户端的广播,然后向客户端发送本机的IP与服务端口,让客户端接入到服务器进行聊天,检测用户名是否合法(重复),服务器责接收来自客户端的聊天信息,并根据用户的需求发送给指定的人或所有人,能够给出上线下线提示。客户端能够发出连接请求,能编辑发送信息,可以指定发给单人或所有人,能显示聊天人数,上线下线用户等。 二、 通信规范的制定 服务请求规范: 服务器端: (1) 创建一个UDP的套接字,接受来自客户端的广播请求,当请求报文内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”时,接受请求,给客户端发送本服务器TCP聊天室的端口号。 (2) 创建一个主要的TCP协议的套接字负责客户端TCP连接 ,处理它的连接请求事件。 (3)在主要的TCP连接协议的套接字里面再创建TCP套接字保存到动态数组里,在主要的套接字接受请求后 ,就用这些套接字和客户端发送和接受数据。 客户端: (1) 当用户按“连接”按钮时,创建UDP协议套接字,给本地计算机发广播,广播内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”。 (2)当收到服务器端的回应,收到服务器发来的端口号后,关闭UDP连接。根据服务器的IP地址和端口号重新创建TCP连接。 故我思考:客户端一定要知道服务器的一个端口,我假设它知道服务器UDP服务的端口,通过发广播给服务器的UDP服务套接字,然后等待该套接字发回服务器TCP聊天室服务的端口号,IP地址用ReceiveForom也苛刻得到。 通信规范 通信规范的制定主要跟老师给出的差不多,并做了一小点增加: (增加验证用户名是否与聊天室已有用户重复,在服务器给客户端的消息中,增加标志0) ① TCP/IP数据通信 --- “聊天”消息传输格式 客户机 - 服务器 (1)传输“用户名” STX+1+用户名+ETX (2) 悄悄话 STX+2+用户名+”,”+内容+ETX (3) 对所有人说 STX+3+内容+ETX 服务器- 客户机 (0)请求用户名与在线用户名重复 //改进 STX+0+用户名+EXT (1)首次传输在线用户名 STX+1+用户名+ETX (2)传输新到用户名 STX+2+用户名+ETX (3)传输离线用户名 STX+3+用户名+ETX (4)传输聊天数据 STX+4+内容+ETX (注:STX为CHR(2),ETX 为CHR(3)) 三、 主要模块的设计分析 四、 系统运行效果 (要求有屏幕截图) 五、 心得与体会

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值