Erlang 聊天室程序(七) 获取在线用户

时间:2022-06-01 17:55:45

              先定义消息格式如下:

              请求: #message{type="get",subject="clientinfo",content="all"}

              响应:#message{type="result",subject="clientinfo",content=[#clientinfo,#clientinfo,.....]}

              修改客户端发送请求消息部分:

             

clientThread.sendMsg(new Message("get","client","","clientinfo","all"));

              修改服务器端,给chat_room添加一个获取所有在线用户的方法:

            

getMembers(Message)->
	gen_server:call(?MODULE, {get_member,Message})
.

             在路由模块根据message.type 和message.subject将请求信息路由到以上方法

routeMessage(Type,Sub,Message)->
		case Type of
		"msg"->
				case Sub of
					"chat"->
						io:format("message_router:route to chat_room:broadcast:~p~n",[Message]),
						chat_room:broadCastMsg(Message);					
					_Els->
						io:format("unkonw msssage subject:~p~n",[Sub])
				end;
		"set"->
				case Sub of
					"clientinfo"->
						chat_room:setUserInfo(Message);					
					_Els->
						io:format("unkonw msssage subject:~p~n",[Sub])
				end;
		"get"->
				case Sub of
					"clientinfo"->
						chat_room:getMembers(Message);
				    _Els->
						io:format("unkonw msssage subject:~p~n",[Sub])
			    end;			
		_Els->
			{error,"wrong message type"}
	    end
.
              chat_room中处理get_member的调用,在里面定义一个本地方法getClient使用client_manager以#clientinfo格式获取在线用户

              chat_room.erl:

handle_call({get_member,Msg},From,State)->
	#message{content=Content}=Msg,
	case binary_to_list(Content) of
		"all"->
			List=getClient([],[]),		
			#message{from=Id}=Msg,
			TheFrom=client_manager:getNick(Id),
			Message=Msg#message{type="result",from=TheFrom,subject="clientinfo",content=List},
			{Pid,_}=From,
			Pid!{get_member,Message}; 
		_Els->
			ok
	end,
	{reply,ok,State}
;
getClient(Key,UList)->
    case client_manager:getNextClient(Key) of
        [Record]->
            Next=Record#clientinfo.id,
            io:format("record is:~p~n",[Record]),
            Json=util_SetInfoParas:deparaElement(Record),
            io:format("clientSession found:~p~n",[Record]),
            NewUList=[Json|UList],
            getClient([Next],NewUList);
        []->
            UList
    end
.


                这里为了方便后面的解析,返回的客户信息需要预先编码为JSONString在Erlang下decode后的格式,所以根据需要在util_setInfoParas.erl中定义了deparaElement/1方法

deparaElement(Record)->
	#clientinfo{nick=Nick,
				sex=Sex,
				age=Age,
				province=Province,
				city=City,
				posx=Px,
				posy=Py}=Record,
	{obj,[
			 {"nick",list_to_binary(setDef(Nick,"s"))},			
			 {"sex",setDef(Sex,"i")},
			 {"age",setDef(Age,"i")},
			 {"province",list_to_binary(setDef(Province,"s"))},
			 {"city",list_to_binary(setDef(City,"s"))},
			 {"posx",setDef(Px,"i")},
			 {"posy",setDef(Py,"i")}
			 ]}	
.

setDef(Val,Type)->
	Defv=case Type of
		      "s"->
				"";
		 	  "i"->
				0;
			  "l"->
				[]
		end,
			
	case Val of
		undefined->
			Defv;
		Els->
			Val
	end
.
              chat_room处理后会将结果打包成一个Message发送给对应的客户端进程,客户端进程再发送给最终的客户端

handle_info({get_member,Message},State)->
	io:format("client_session-getmember result ~p~n",[Message]),
	sendMsg(Message,State),
	{noreply,State}
;

              再修改客户端JAVA代码,将收到的JSONString转换为Bean对象。这里专门新建一个类GetUserInfo表示接收到的result信息

package com.kinglong.socket.data;

import java.util.ArrayList;
import java.util.Date;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class GetUserInfo extends Packet{
	
	ArrayList<ClientInfo> content=null;
	
	public GetUserInfo(){
		this.json=new JSONObject();
		setType("get");
		setSubject("clientinfo");	
		setCreationDate(new Date());
	}
	
	public GetUserInfo(ArrayList<ClientInfo>list){
		this.json=new JSONObject();
		setType("get");
		setSubject("clientinfo");	
		setCreationDate(new Date());
		setContent(list);
	}

	public ArrayList<ClientInfo> getContent() {		
		JSONArray array=json.getJSONArray("content");
				
		ArrayList<ClientInfo> infos = new ArrayList<ClientInfo>();
		int size=array.size();
		for(int i=0;i<size;i++){
			JSONObject obj=array.getJSONObject(i);
			infos.add((ClientInfo)JSONObject.toBean(obj, ClientInfo.class));
		}
		
		if(array==null){
			return null;
		}
		else{
			if(content!=null){
				return content;
			}
			else{
				content=infos;
				return content;
			}
		}							
	}

	public void setContent(ArrayList<ClientInfo> clients) {
		if(clients!=null){
			this.content = clients;
		}
		this.json.put("content", clients);		
	}			
}
            再修改客户端接收部分的代码,将对应类型的消息解析

public void run() {
		// TODO Auto-generated method stub
		InputStreamReader reader = new InputStreamReader(inst);
		BufferedReader bfreader = new BufferedReader(reader);
		while(isrunning){
			String str=null;
			try {
				byte[] data =new byte[1024];
				int len =0;
				while((len=inst.read(data))>0){					
					str=new String(data).trim();
					Iterator<JSONObject> it =JSONParaser.getString(str);
					while(it.hasNext()){
						JSONObject obj=it.next();
						if("msg".equals(obj.get("type"))){
							Message msg =(Message)JSONObject.toBean(obj,Message.class);
							mf.recMsg(msg);
						}						
						else if("result".equals(obj.get("type"))&&"clientinfo".equals(obj.get("subject"))){

							Map<String,Class>mapclass = new HashMap<String,Class>();
							mapclass.put("content", ClientInfo.class);
							GetUserInfo info=(GetUserInfo)JSONObject.toBean(obj,GetUserInfo.class,mapclass);
							Iterator<ClientInfo> clients=info.getContent().iterator();
							while(clients.hasNext()){
								ClientInfo in =clients.next();
								mf.recMsg("there are client nick:"+in.getNick());
							}							
						}
					}																	
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				System.out.println("recMsg error"+e.getMessage());
				isrunning=false;
			}
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}			

测试结果如下:

启动一个客户端,修改其昵称为clientA

Erlang 聊天室程序(七) 获取在线用户

再启动一个客户端,修改昵称为clientB

Erlang 聊天室程序(七) 获取在线用户

clientB客户端获取当前在线用户(这里只打印昵称)

Erlang 聊天室程序(七) 获取在线用户