Erlang写服务器,连接所有的客户端,只要收到一个客户端的消息,就会群发到其他客户端。
C#写客户端,可以多个客户端,发送消息到服务器。
1.Erlang服务器
知识点:
Erlang使用{packet,N}后,会自动在数据前面增加N个字节。
{active,true},{active,false},{active,once},分别是主动、被动、半阻塞三种模式:
% {active,true} 创建一个主动套字节(非阻塞);
% {active,false} 创建一个被动套字节(阻塞),如果为false表必须手工处理阻塞,否则阻塞在此处无法收听,当前我无法处理;
% {active, once} 创建一个一次性被动套字节(阻塞),只收听一次后堵塞,必须调用inet:setopts(Socket, [{active, once}]),后才可收听下一条,创建一个主动套字节仅接收一条消息,如想接收下一条必须再次激活(半阻塞)。
1. active(主动消息接收):非阻塞。当数据到达时系统会向控制进程发送{tcp, Socket, Data}消息。控制进程无法控制消息流;
2. passive(被动消息接收):阻塞。控制进程必须主动调用recv()来接收消息。可以控制消息流;
3. active once(混合消息接收):半阻塞。这种模式是主动的但仅针对一个消息,在控制进程收到一个消息后,必须显式调用inet:setopts(Socket, [{active, once}])来重新
激活以接收下一个消息。可以进行流量控制。这种模式相对于被动模式来说,有个优点是可以同时等待多个socket的数据。
http://www.2cto.com/kf/201304/202413.html
http://blog.csdn.net/pkutao/article/details/8572216
module(hjh_server).
-compile(export_all).
%%http://hideto.iteye.com/blog/226639
start_nano_server() ->
%%注册一个进程到pid
register(pid,spawn(fun()->clients([]) end)),
%%监听30087的端口
{ok, LSocket} = gen_tcp:listen(30087, [binary, {packet, 0}, %% (6)
{reuseaddr, true},
{active, false}]),
loop(LSocket).
loop(LSocket) ->
%%连接,得到客户端的Socket
{ok, Socket} = gen_tcp:accept(LSocket), %% (7)
spawn(fun()->handle_client(Socket) end),
pid!{connect,Socket},
loop(LSocket).
handle_client(CSocket)->
%%接受数据,若为{ok,Data}则发送
case gen_tcp:recv(CSocket,0) of
{ok,Data}->
io:format("Socket success:~w~n",[Data]),
pid!{data,Data},
handle_client(CSocket);
{error,_}->
pid!{disconnect,CSocket}
end.
clients(Sockets)->
receive
{connect,Socket}->
io:format("Socket connected:~w~n",[Socket]),
NewSockets=[Socket | Sockets];
{disconnect,Socket}->
io:format("Socket disconnected:~w~n",[Socket]),
NewSockets=lists:delete(Socket,Sockets);
{data,Data}->
send_data(Sockets,Data),
NewSockets=Sockets
end,
clients(NewSockets).
%%群发送,Sockets是所有保存的Socket。
send_data(Sockets,Data)->
SendData=fun(Socket)->
gen_tcp:send(Socket,Data)
end,
lists:foreach(SendData,Sockets).
2.C#客户端
public partial class Form1 : Form
{
Socket socket;
private static byte[] result = new byte[1024];
public Form1()
{
InitializeComponent();
IPAddress ip = IPAddress.Parse("127.0.0.1");
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
socket.Connect(new IPEndPoint(ip, 30087));
socket.Send(Encoding.UTF8.GetBytes("TTTT"));
Thread thread = new Thread(ReceiveMessage);
thread.IsBackground = true;
thread.Start();
}
private void button1_Click(object sender, EventArgs e)
{
String str;
if (textBox2 != null || !textBox2.Equals(""))
{
str = textBox2.Text;
textBox1.Text += str + Environment.NewLine;
socket.Send(Encoding.UTF8.GetBytes(str));
}
}
private void ReceiveMessage()
{
while (true)
{
try
{
int receiveNumber = socket.Receive(result);
AddText("接受服务器端消息:" +
Encoding.UTF8.GetString(result, 0, receiveNumber));
}
catch (Exception ex)
{
AddText(ex.Message);
socket.Shutdown(SocketShutdown.Both);
socket.Close();
break;
}
}
}
private delegate void MessageDelegate(string message);
private void AddText(string message)
{
if (textBox1.InvokeRequired)
{
MessageDelegate d = new MessageDelegate(AddText);
textBox1.Invoke(d, new object[] { message });
}
else
{
textBox1.Text += message + Environment.NewLine;
}
}
}
示意图: