erlang gen_tcp 聊天室(chat节点)

chat节点实现的原理和holl节点实现的原理大致相同。都是从node_connect节点上得到数据,处理之后,把其节点上的数据发给node_connect节点,通过node_connect节点与客户端进行交互。

chat节点的源码如下

%% @author cb1187
%% @doc @todo Add description to opt_chat.


-module(opt_chat).

%% ====================================================================
%% API functions
%% ====================================================================
-behaviour(gen_server). 
-export([]).
%% gen_server callbacks  
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,  
     terminate/2, code_change/3]).  
-compile(export_all).

-define(Ets_Users,opt_chat_ets_users).


-define(Server_Chat,chat).

-define(Node_Node,node@simsunny).
-define(Server_Node,node).

-define(Node_Holl,holl@simsunny).
-define(Server_Holl,holl).


%% ====================================================================
%% Internal functions
%% ====================================================================


s() -> gen_server:start_link({local,?Server_Chat}, ?MODULE, [], []).  
stop()  -> gen_server:call(?Server_Chat, stop). 

init([])->
	
	io:format("init pid:~p~n",[self()]),
	ets:new(?Ets_Users, [set,public,named_table]),
	{ok,[]}.


%%register
handle_call({reigister,register_success,{{user,Name},{socket,Socket}}}, _From,Tab)->
	
	io:format("------------------opt_chat(register)-------------------\n"),
	ets:insert(?Ets_Users, {Name,Socket}),
	{reply, ok, Tab}; 
%%login
handle_call({login,success,{{user,Name},{scoket,Socket}}}, _From,Tab)->
	
	io:format("------------------opt_chat(login)-------------------\n"),
	ets:insert(?Ets_Users, {Name,Socket}),
	{reply, ok, Tab}; 
%%get_all_users
handle_call({get_all_users,{socket,Socket},{server_Name,Server_name}}, _From,Tab)->
	
	io:format("------------------opt_chat(get_call)-------------------\n"),
	List_ets=ets:tab2list(?Ets_Users),
	List_name=get_name_list(List_ets,[]),
	Info={get_all_users,List_name,{socket,Socket}},
	gen_server:cast({Server_name,?Node_Node}, Info),
	{reply, ok, Tab}; 

%%chat_room
handle_call({chat,{name,Name},{content,Msg},{server_Name,Server_name}}, _From,Tab)->
	
	io:format("------------------opt_chat(chat_room)-------------------\n"),
	List_ets=ets:tab2list(?Ets_Users),
	List=lists:keydelete(Name, 1, List_ets),
	Request_node={chat,{name,Name},{content,Msg},List},
	gen_server:cast({Server_name,?Node_Node}, Request_node),
	io:format("to_all_person:~p~n", [List]),
	{reply, ok, Tab}; 

%%create group
handle_call({chat_group,{name,Name},{list,List},{msg,Content},{server_Name,Server_name}}, _From,Tab)->
	
	io:format("------------------opt_chat(chat_group)-------------------\n"),
	List_has_chekt=check_gr(List,[],[]),
	{{in,List_node},{no,List_node_no}}=List_has_chekt,
	Request_node={chat_gr,{name,Name},{content,Content},List_node},
	gen_server:cast({Server_name,?Node_Node}, Request_node),
	io:format("to_group_in:~p~n", [List_node]),
	io:format("to_group_not:~p~n", [List_node_no]),
%% 	gen_server:call({?Server_Node,?Node_Node}, Request_node),
	{reply, ok, Tab}; 

%%quite
handle_call({quite,{socket,Socket},{server_name,_Server_name}}, _From,Tab)->
	
	io:format("------------------opt_chat(quite)-------------------\n"),
%% 	List_ets=ets:tab2list(?Ets_Users),
%% 	List_name=get_name_list(List_ets,[]),
%% 	Info={get_all_users,List_name,{socket,Socket}},
%% 	io:format("info:~p~n", [Info]),
%% 	gen_server:cast({Server_name,?Node_Node}, Info),
	List=ets:tab2list(?Ets_Users),
	case lists:keysearch(Socket, 2, List) of
		{value,{Name,_S}}->
			ets:delete(?Ets_Users,Name),
			Request_holl={quite,{name,Name}},
			gen_server:call({?Server_Holl,?Node_Holl}, Request_holl);
		{false}->
			io:format("error in \n: 
					   moudle: opt_chat \n
					   fun: handle_call({quite,{socket,Socket}}, _From,Tab)")
	end,
	{reply, ok, Tab}; 

		

handle_call(stop, _From, Tab) ->  
    {stop, normal, stopped, Tab}.  
  
handle_cast(_Msg, State) -> {noreply, State}.  
handle_info(_Info, State) -> {noreply, State}.  
terminate(_Reason, _State) -> ok.  
code_change(_OldVsn, State,_Extra) -> {ok, State}.


get_name_list([{Name,_Socket}|T],Acc)->
	get_name_list(T, [Name|Acc]);
get_name_list([],Acc)->
	lists:reverse(Acc).

%%just test check_gr
ts()->
	ets:new(?Ets_Users, [set,public,named_table]),
	ets:insert(?Ets_Users, {wuzhao,wudong}),
	ets:insert(?Ets_Users, {conghui,wuzhao}),
	ets:insert(?Ets_Users, {sim,sunny}).


check_gr([Key_name|T],Acc_in,Acc_not)->
	io:format("Key_name:~p~n",[Key_name]),
	case ets:lookup(?Ets_Users, Key_name) of
		[{Name,Socket}]->
			check_gr(T,[{Name,Socket}|Acc_in],Acc_not);
		[]->
			check_gr(T,Acc_in,[Key_name|Acc_not])
			
	end;

check_gr([],Acc_in,Acc_not)->
	io:format("Acc_in:~p~n", [Acc_in]),
	io:format("Acc_not:~p~n", [Acc_not]),
	List={{in,Acc_in},{no,Acc_not}},
	List.
		
		
注意:
ets:new(?Ets_Users, [set,public,named_table]),
这个ets表,表示的是现在在线的客户端的{姓名,端口号}

问题:怎么样动态的创建节点?比如一个chat节点连接的用户太多,比如大于100个客户端的连接,就可以在代码中新开启一个chat的节点,来处理其他的客户端连接?这个在erlang中可以实现么?

客户端的代码我会打包给大家的~~

欢迎转载,请注明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Erlang中,我们可以使用`gen_tcp`模块来实现TCP客户端。下面是一个简单的例子,展示如何使用`gen_tcp`模块来连接到一个服务端: ```erlang -module(tcp_client). -export([start/1]). start(Host) -> {ok, Socket} = gen_tcp:connect(Host, 80, [binary, {packet, 0}]), gen_tcp:send(Socket, "GET / HTTP/1.0\r\n\r\n"), receive_data(Socket), gen_tcp:close(Socket). receive_data(Socket) -> case gen_tcp:recv(Socket, 0) of {ok, Data} -> io:format("~s", [Data]), receive_data(Socket); {error, closed} -> ok end. ``` 在上面的例子中,`gen_tcp:connect`函数用于连接到指定的服务端。`Host`参数是服务端的IP地址或域名,`80`是服务端的端口号。`[binary, {packet, 0}]`选项说明我们要传输二进制数据,且数据包不需要打包。 一旦连接建立成功,我们就可以使用`gen_tcp:send`函数向服务端发送数据了。在这个例子中,我们发送了一个HTTP GET请求。接着,我们调用了`receive_data`函数来接收服务端返回的数据。`gen_tcp:recv`函数用于接收服务端发送的数据。`0`参数表示接收的数据包没有大小限制。如果接收到数据,我们就打印出来,并继续调用`receive_data`函数来接收更多的数据。如果服务端关闭了连接,`gen_tcp:recv`函数会返回错误信息`{error, closed}`,我们就可以关闭连接了。 在使用`gen_tcp`模块时,我们需要注意以下几点: - 为了避免阻塞,在发送和接收数据时,我们可以使用`gen_tcp:send/2`和`gen_tcp:recv/2`函数的阻塞模式,即将第二个参数设置为`0`。这样,如果没有数据可发送或接收,函数就会马上返回。 - 如果我们需要发送和接收大量的数据,应该使用`{packet, N}`选项来打包数据。这个选项会将数据分成大小为N的块,并且在每个块前面添加4个字节的头部,用于表示这个块的大小。这样可以避免粘包问题。 - 在发送和接收数据时,我们应该按照服务端和客户端的协议来组织数据包。如果协议有变化,我们也需要修改代码来适应新的协议。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值