Socket客户端与服务端通信私聊

客户端:

/**
 * 将聊天室客户端内容独立完成一次.
 * 下面内容可以选做:
 * 修改代码,使聊天室可以实现用户自定义昵称,
 * 以及私聊功能。
 * 
 * 参考思路:
 * 客户端连接服务端后,要求用户输入一个昵称,
 * 然后将改昵称发送给服务端,服务端那边读取到
 * 客户端发送的第一个字符串认为是昵称。
 * 
 * 私聊功能可以定义格式,例如:
 * @张三:你好
 * 服务端在读取客户端发送过来的昵称时,需要进行
 * 解析,分解出昵称与聊天内容,然后将该聊天内容
 * 单独发送给指定昵称的用户。
 * 服务端的输出流需要使用Map进行维护,而不能再
 * 使用List,Map的key可以是该用户昵称,value
 * 为该用户输出流。
 * @author Xiloer
 *
 */
public class Client {
	private Socket socket;
	public Client() throws IOException{
		socket=new Socket("176.195.107.88",8088);
		System.out.println("已连接服务器!");
	}
	private void inputNickName(Scanner scan) throws  Exception	
	{
		String nickName = null;
		//创建输出流
		PrintWriter pw = new PrintWriter(
				new OutputStreamWriter(socket.getOutputStream(),
						"UTF-8"),true);
		//创建输入流
		BufferedReader br = new BufferedReader(
				new InputStreamReader(
						socket.getInputStream(),"UTF-8"));
		
		while(true)
		{	
			System.out.println("请创建您的昵称:");
			nickName = scan.nextLine();
			if (nickName.trim().equals(""))
			{
				System.out.println("昵称不得为空");
			}
			else 
			{	
				pw.println(nickName);
				String pass = br.readLine();
				if(pass!=null&&!pass.equals("OK"))
				{
					System.out.println("昵称已经被占用,请更换!");
					break;
				}
				else
				{
					System.out.println("你好!"+nickName+"可以开始聊天了");
					break;
				}
			}
		}
	}
	

	public void start(){
		try {
			System.out.println("请输入:");
			Scanner scanner=new Scanner(System.in);
			inputNickName(scanner);
			
			ServerHandler server=new ServerHandler();
			Thread t=new Thread(server);
			t.start();
			
			
			OutputStream os = socket.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
			PrintWriter pw = new PrintWriter(osw,true);
			
			while(true)
			{
				pw.println(scanner.nextLine());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
		
			if(socket !=null)
			{
				try
				{
					socket.close();
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) throws IOException {
		Client client=new Client();
		  client.start();
	}
	
    private class ServerHandler implements Runnable{

		public void run() {
			try {
				InputStream is = socket.getInputStream();
				InputStreamReader isr = new InputStreamReader(is,"UTF-8");
				BufferedReader br = new BufferedReader(isr);
				String msgString = null;
				while((msgString = br.readLine())!= null)
				{
					System.out.println(msgString);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}

服务端:

/**
 * 将聊天室服务端内容独立完成一次
 * 下面内容可以选做:
 * 配合客户端实现支持昵称与私聊功能
 * @author Xiloer
 *
 */
public class Server {
	private ServerSocket server;
//	private List<PrintWriter> allOut;
	private Map<String,PrintWriter> allOut;
public Server(){
	try {
		server=new ServerSocket(8088);
		allOut = new HashMap<String, PrintWriter>();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
}
private void addOut(String key,PrintWriter value)
{
	synchronized(this)
	{
		allOut.put(key, value);
	}
}

private synchronized void removeOut(String  key)
{
	allOut.remove(key);
	System.out.println("当前在线人数为:"+ allOut.size());
}
private synchronized void sendMsgToAll(String message)
{
	for(PrintWriter out: allOut.values())
	{
		out.println(message);
		System.out.println("当前在线人数为:"+ allOut.size());
	}
}


private synchronized void sendMsgToPrivate(String nickname,String message)
{
	PrintWriter pw = allOut.get(nickname); //将对应客户端的聊天信息取出作为私聊内容发送出去
	if(pw!=null)
	{
		pw.println(message);
		System.out.println("1111111111111111111111111111111111111");
		System.out.println("当前在线私聊人数为:"+ allOut.size());
	}		
}


public void start(){
	try{
		
		while(true){
		System.out.println("等待客户端连接.......");
		Socket socket=server.accept();
		System.out.println("客户端已连接!");
		ClientHandler client=new ClientHandler(socket);
		Thread t=new Thread(client);
		t.start();
		}
	}catch(Exception e){
		e.printStackTrace();
	}
}
public static void main(String[] args) {
	Server server=new Server();
	server.start();
}
private class ClientHandler implements Runnable{
    private Socket socket;
    private String host;
    private String nickName;
   public ClientHandler(Socket socket){
    	this.socket=socket;
    	InetAddress adress=socket.getInetAddress();
    	host=adress.getHostAddress();
    }
    private String getNickName() throws Exception
	{
		try
		{
			//服务端的输入流读取客户端发送来的昵称输出流
			InputStream in = socket.getInputStream();
			InputStreamReader isr = 
					new InputStreamReader(in,"UTF-8");
			BufferedReader bReader = new BufferedReader(isr);
			//服务端将昵称验证结果通过自身的输出流发送给客户端
			OutputStream out = socket.getOutputStream();
			OutputStreamWriter iosw = 
					new OutputStreamWriter(out,"UTF-8");
			PrintWriter ipw = new PrintWriter(iosw,true);
			//读取客户端发来的昵称
			String nameString = bReader.readLine();
			while(true)
			{
				if(nameString.trim().length()==0)
				{
					ipw.println("FAIL");
				}
				if(allOut.containsKey(nameString))
				{
					ipw.println("FAIL");
				}
				else 
				{
					ipw.println("OK");
					return nameString;
				}
			}
		}
		catch(Exception e)
		{
			throw e;
		}
	}
	
	public void run()
	{
		PrintWriter pw = null;
		try 
		{
			/*
			* 通过客户端的Socket获取客户端的输出流
			* 用来将消息发送给客户端
			*/
			OutputStream os = socket.getOutputStream();
			OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8");
			pw = new PrintWriter(osw,true);
			
			/*
			* 将客户昵称和其所说的话作为元素存入共享集合HashMap中
			*/
			nickName = getNickName();
			addOut(nickName, pw);
			Thread.sleep(100);
			
			/*
			* 服务端通知所有客户端,某用户登录
			*/
			sendMsgToAll("[系统通知]:欢迎**"+nickName+"**登陆聊天室!");
			
			/*
			* 通过客户端的Socket获取输入流
			* 读取客户端发送来的信息
			*/
			InputStream is = socket.getInputStream();
			InputStreamReader isr = new InputStreamReader(is,"UTF-8");
			BufferedReader br = new BufferedReader(isr);
			String msgString = null;
			
			while((msgString = br.readLine())!=null)
			{
				//验证是否是私聊
				if(msgString.startsWith("@"))
				{
					/*
					* 私聊格式:@昵称:内容
					*/
					int index = msgString.indexOf(":");
					if(index >=0)
					{
						//获取昵称
						String name = msgString.substring(1,index);
						String info = msgString.substring(index+1,msgString.length());
						info = nickName + "对你说:"+ info;
						//将私聊信息发送出去
						sendMsgToPrivate(name, info);
						//服务端不在广播私聊的信息
						continue;
					}
				System.out.println("已输出");
				}
				/*
				* 遍历所有输出流,将该客户端发送的信息转发给所有客户端
				*/
				System.out.println(nickName+"说:"+ msgString);
				sendMsgToAll(nickName+"说:"+ msgString);
			
		} 
		}
		catch (Exception e) 
		{
			/*
			* 因为Win系统用户的客户端断开连接后,br.readLine()方法读取
			* 不到信息就会抛出异常,而Linux系统会持续发送null;
			* 因此这里就不在将捕获的异常抛出了。
			*/
		}
		finally
		{
			/*
			* 当执行到此处时,说明客户端已经与服务端断开连接
			* 则将该客户端存在共享集合中的输出流删除
			*/
			removeOut(nickName);
			/*
			* 通知所有客户端,某某客户已经下线
			*/
			sendMsgToAll("[系统通知]:"+nickName + "已经下线了。");
			
			/*
			* 关闭socket,则通过Socket获取的输入输出流也一同关闭了
			*/
			if(socket!=null)
			{
				try
				{
					socket.close();
				}
				catch(IOException e)
				{
					e.printStackTrace();
				}
			}	
		}
	}
}
    
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值