群聊内实现私聊功能

首先我们想到的是,消息发过来,我怎么知道是公聊消息还是私聊消息呢。所以,这里需要对消息进行处理,比如说在消息前后都加上一些特殊的字符,我们称为协议字符。为此,我们可以定义一个接口,专门来定义协议字符。

第二个问题就是,如果是私聊信息,客户端会将目的用户(私聊对象)发给服务器端,那么服务器端是如何将找到那个目的用户的呢。这里,很明显,我们需要建立一个用户和Socket的映射关系,所以我们采用了map,但是这里的map我们需要改进一下,因为其实我们这里不仅仅是key不能重复,而且value也不能重复,我们也需要通过value能够查找到key,所以我们进行了改进。

还有一点针对本实现需要指出的是,服务器子线程负责接收和发送消息,这里面也包括客户端首次建立连接的时候,需要判断用户名是否重复,也就是要保证key不重复,于此想对应的,客户端在首次建立连接时,其需要进行不断的尝试,直到提供的名字不重复为止。

代码如下:

public interface CrazyitProtocol {
 public static final int PROTOCOL_LEN=2; //默认的类型就是public static final,不加也是可以的   public static final String MSG_ROUND="△▽";  public static final String USR_ROUND="□☆";  public static final String LOGIN_SUCCESS="☆▷";  public static final String NAME_REP="-1";  public static final String PRAVITE_ROUND="◆★";  public static final String SPLIT_SIGN="☀"; }
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;


public class CrazyitMap<K,V> extends HashMap<K,V> {  // 根据value来删除指定项  public void removeByValue(Object value)  {   for(Object key :keySet())   {    if(get(key)==value||get(key).equals(value))    {     remove(key);     break;    }   }  }   // 获取value集合  public Set<V> valueSet()  {   Set<V> result=new HashSet<V>();   for(Object key : keySet())   {    result.add(get(key));   }   return result;  }   // 重写HashMap的put方法,该方法不允许value重复  public V put(K key,V value)  {   for(V val : valueSet())   {    if(val==value||val.equals(value))    {     throw new RuntimeException("MyMap实例中不允许有重复value");    }   }   return super.put(key, value);  }   // 通过value查找key  public K getKeyByValue(Object value)  {   for(K key : keySet())   {    if(get(key)==value||get(key).equals(value))    {     return key;    }   }   return null;  } }
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;


public class Server {   private static final int PORT=30000;  public static CrazyitMap<String,PrintStream> clients=new CrazyitMap<>();   void init()  {   try (    ServerSocket ss=new ServerSocket(PORT);   )   {    while(true)    {     Socket s=ss.accept();     new Thread(new ServerThread(s)).start();    }      }catch (IOException e) {    // TODO Auto-generated catch block    System.out.println("服务器启动失败,是否端口被占用?");   }  }  public static void main(String[] args) {   // TODO Auto-generated method stub   Server s=new Server();   s.init();  } }
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket; public class ServerThread implements Runnable {   private Socket s;  private BufferedReader br=null;  private PrintStream ps=null;   public ServerThread(Socket s)  {   this.s=s;    }  @Override  public void run() {   // TODO Auto-generated method stub     try {    br=new BufferedReader(new InputStreamReader(s.getInputStream()));    ps=new PrintStream(s.getOutputStream());    String content=null;    while((content=br.readLine())!=null)    {     if(content.startsWith(CrazyitProtocol.USR_ROUND) //发过来的是名字信息       &&content.startsWith(CrazyitProtocol.USR_ROUND))     {      String userName=getRealMsg(content);      if(Server.clients.containsKey(userName)) // 姓名重复      {       System.out.println("重复");       ps.println(CrazyitProtocol.NAME_REP);            }      else // 姓名不重复      {       System.out.println("成功");       Server.clients.put(userName, ps);       ps.println(CrazyitProtocol.LOGIN_SUCCESS);      }     }     else if(content.startsWith(CrazyitProtocol.PRAVITE_ROUND)       &&content.startsWith(CrazyitProtocol.PRAVITE_ROUND))// 发过来的是实际的消息,且为私聊消息     {      String userAndMsg=getRealMsg(content);      String userName=userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[0];      String Msg=userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[1];      // 获取私聊用户的输出流      Server.clients.get(userName).println(Server.clients.getKeyByValue(ps)        +"悄悄的对你说"+Msg);          }     else // 公聊信息     {      String Msg=getRealMsg(content);      for(PrintStream ps : Server.clients.valueSet())  

转载于:https://www.cnblogs.com/yupf/p/5858810.html

一共包括10个以上的聊天程序版本!绝对物有所值! 为感谢大家长期的支持,我将下载所需的资源分下调为2。网络聊天程序设计(可选)  实验要求 1、分析典型网络聊天应用软件(如QQ、MSN等)的实现原理,模拟设计一套网络聊天应用程序,必须实现以下功能: ①按照C/S结构分别设计服务端程序和客户端程序; ②服务端通过图形用户界面实现对服务器的控制,负责维护用户帐户和用户群,并维护用户信息、维持客户端之间的端对端通信和群聊通信、适时维护用户在线信息,并能够发送广播消息。 2、增加尽可能多的功能,用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 3、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。  实验提示 1、客户端之间的通信是通过服务器进行转发的,对于两个客户端,服务器需要创建两个套接字分别维持与客户端之间的连接。当客户端需要向另一个客户发送消息时,它首先将消息发送到服务器,由服务器根据目标用户帐户转发到目标主机。 2、群聊是采用多播技术实现的,也可以采用单播技术实现,但是服务器开销会增加。具体说来,若采用组播技术,当服务端收到来自一个客户端的消息后,向预先分配的该组组播地址转发该消息。若采用单播技术,服务端需要向该组内的所有客户端一一转发该消息。 3、广播消息通过广播方式发送由服务端创建的消息。 4、服务端根据客户的连接和断开情况,实时向其它客户端发送用户在线信息。 实验题目二:自选网络通信程序设计(可选)  实验要求 可以自选与网络通信相关的设计题目,要求如下: 1、在确定实验题目、设计内容以及设计功能指标要求后,向实验指导教师提交书面申请,由实验指导教师根据所选实验题目的难度和工作量确定立题后方能开始实验。 2、选择的实验题目必须具有一定综合性,并能够利用网络通信原理加以解决,同时需要具备一定的工作量。 3、设计的结果要求用户界面友好,操作简便,代码设计遵从程序设计规范,易读性强,对关键过程和代码进行标注说明。 4、程序设计过程遵从软件工程规范,有需求分析、系统设计和详细设计过程,有相应的规范化说明文档。 5、严禁抄袭别人成果,但可以部分借鉴。
项目简介: 采用I/O复用技术select实现socket通信,采用多线程负责每个客户操作处理,完成Linux下的多客户聊天室! OS:Ubuntu 15.04 IDE:vim gcc make DB:Sqlite 3 Time:2015-12-09 ~ 2012-12-21 项目功能架构: 1. 采用client/server结构; 2. 给出客户操作主界面(注册、登录、帮助和退出)、登录后主界面(查看在线列表、私聊群聊、查看聊天记录、退出); 3. 多客户可同时连接服务器进行自己操作; ##服务器端## 1. server.c:服务器端主程序代码文件; 2. config.h:服务器端配置文件(包含需要的头文件、常量、数据结构及函数声明); 3. config.c:服务器端公共函数的实现文件; 4. list.c:链表实现文件,用于维护在线用户链表的添加、更新、删除操作; 5. register.c:服务器端实现用户注册; 6. login.c:服务器端实现用户登录; 7. chat.c:服务器端实现用户的聊天互动操作; 8. Makefile:服务器端make文件,控制台执行make命令可直接生成可执行文件server ##客户端## 1. client.c:客户端主程序代码文件; 2. config.h:客户端配置文件(包含需要的头文件、常量、数据结构及函数声明); 3. config.c:客户端公共函数的实现文件; 4. register.c:客户端实现用户注册; 5. login.c:客户端实现用户登录; 6. chat.c:客户端实现用户的聊天互动操作; 7. Makefile:客户端make文件,控制台执行make命令可直接生成可执行文件client;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值