2014年(9)
分类: 其他平台
2014-09-14 11:45:23
erlang服务端 quick_server.erl:
-module(quick_server).
-export([
start/0,
start_accepters/2,
server_accept/2,
client_loop/2,
test_connect/0,
send_login/2
]).
-define(PORT, 8888).
-define(MSG_ECHO(F,D), io:format("MODULE: ~p LINE: ~p PID: ~p " ++ F, [?MODULE, ?LINE, self()|D])).
start() ->
start(?PORT).
start(Port) ->
Num = erlang:system_info(schedulers),
case gen_tcp:listen(Port, [binary, {active, false}, {packet, 0}]) of
{ok, LSock} ->
register(?MODULE, spawn(?MODULE, start_accepters, [LSock, Num])),
{ok, self()};
{error, Reason} ->
{error, Reason}
end.
start_accepters(_, 0) ->
server_loop([]);
start_accepters(LSock, Num) ->
spawn(?MODULE, server_accept, [LSock, Num]),
start_accepters(LSock, Num - 1).
server_loop(Clients) ->
?MSG_ECHO("now Clients: ~p~n", [Clients]),
receive
{login, Socket, Uid, Uname} ->
case lists:keyfind(Socket, 1, Clients) of
false ->
?MSG_ECHO("receive login Uid: ~p Uname: ~p~n", [Uid, Uname]),
LoginData = msg_login(Uid, Uname),
OnlinesData = msg_onlines(Clients),
gen_tcp:send(Socket, OnlinesData),
do_broadcast(Clients, LoginData),
server_loop([{Socket, Uid, Uname}|Clients]);
_ ->
server_loop(Clients)
end;
{logout, Socket} ->
case lists:keytake(Socket, 1, Clients) of
{value, {Socket, Uid, _Uname}, NewClients} ->
?MSG_ECHO("receive logout Uid: ~p~n", [Uid]),
LogoutData = msg_logout(Uid),
do_broadcast(NewClients, LogoutData),
server_loop(NewClients);
false ->
server_loop(Clients)
end
end.
server_accept(LSock, Num) ->
erlang:process_flag(scheduler, Num),
server_accept_acc(LSock, Num).
server_accept_acc(LSock,Num) ->
case gen_tcp:accept(LSock) of
{ok, CSock} ->
Pid = spawn(?MODULE, client_loop, [CSock, Num]),
gen_tcp:controlling_process(CSock, Pid),
server_accept_acc(LSock, Num);
Other ->
io:format("accept has a error: ~w !~n", [Other]),
server_accept_acc(LSock, Num)
end.
client_loop(CSock, Num) ->
erlang:process_flag(scheduler, Num),
client_loop_acc(CSock, <<>>).
client_loop_acc(CSock, Bin) ->
?MSG_ECHO("loop Bin: ~p~n", [Bin]),
inet:setopts(CSock, [{active, once}]),
receive
{tcp, CSock, SocketBin} ->
?MSG_ECHO("receive SocketBin: ~p~n", [SocketBin]),
NewBin = work(<
client_loop_acc(CSock, NewBin);
{tcp_closed, CSock} ->
?MODULE ! {logout, CSock},
io:format("socket ~w closed [~w]~n", [CSock, self()])
end.
work(<
check(BinData, CSock),
work(Bin, CSock);
work(Bin, _CSock) ->
Bin.
check(<
?MSG_ECHO("ProtocolCode: ~p~n", [ProtocolCode]),
gateway(ProtocolCode, Bin, CSock).
% 登陆 Uid: 4 byte, UnameLen: 2 byte, Uname: string(UnameLen byte)
gateway(1001, <
?MODULE ! {login, CSock, Uid, Uname};
gateway(_Code, _Binary, _CSock) ->
?MSG_ECHO("ERROR msg, _Code: ~p _Binary: ~p~n", [_Code, _Binary]).
do_broadcast(Clients, BinData) ->
[ gen_tcp:send(Socket, BinData) || {Socket, _Uid, _Uname} <- Clients].
msg_login(Uid, Uname) ->
BinData = msg_user_base(Uid, Uname),
msg(1002, BinData).
msg_onlines(Clients) ->
Count = length(Clients),
Fun = fun({_Socket, Uid, Uname}, AccBin) ->
Fbin = msg_user_base(Uid, Uname),
<
end,
BinData = lists:foldl(Fun, <
msg(1003, BinData).
msg_logout(Uid) ->
BinData = <
msg(1004, BinData).
msg_user_base(Uid, Uname) ->
UnameLen = byte_size(Uname),
<
msg(MsgCode, BinData1) ->
BinLen = byte_size(BinData1) + 2,
BinData = <
<
test_connect() ->
{ok, Socket} = gen_tcp:connect("127.0.0.1", ?PORT, [binary, {active, true}, {packet, 0}]),
Socket.
send_login(Uid, Uname) ->
BinData = msg_user_base(Uid, Uname),
msg(1001, BinData).
lua客户端 quick_client.lua:
-- quick_client.lua
require("socket")
require("pack")
PACKAGE_LENGTH = 2
receiveStateLength = 0
receiveStateContent = 1
local host = "127.0.0.1"
local port = 8888
local client= assert(socket.connect(host, port))
local protocolCode = 1001
local luid = 2222
local lname = "xxx"
local llenname = string.len(lname)
local pstring = string.pack(">H>I>H>A", protocolCode, luid, llenname, lname)
local plen = string.len(pstring)
local loginPacket = string.pack(">H>A", plen, pstring)
client:send(loginPacket)
function dispatchPacket(curPacket)
packetId = curPacket:readPacketId()
print("packetId is: ", packetId)
end
function createEmptyPacket()
local packet = {packetLen = 0, --包长度(int 类型)
packetLenByteNum = 0, --包长度字节数
packetLenBytes = "", --包长度字节
packetContentByteNum= 0, --包内容字节数
packetContentBytes = "", --包内容字节
packetId = 0, --解析得到的包id
pos = 1, --包内容解到哪个位置了
}
local newpacket = {}
function packet:readPacketId()
if self.packetId == 0 then
self.packetId = self:readUnint16()
end
return self.packetId
end
function packet:readByte()
self.pos, rByte = string.unpack(self.packetContentBytes, ">b", self.pos)
return rByte
end
function packet:readUnint16()
self.pos, rUnint16 = string.unpack(self.packetContentBytes, ">H", self.pos)
return rUnint16
end
function packet:readUnint32()
self.pos, rUnint32 = string.unpack(self.packetContentBytes, ">I", self.pos)
return rUnint32
end
function packet:readString()
stringLen = self:rUnint16()
rString = string.sub(self.packetContentBytes, self.pos, self.pos + stringLen)
self.pos = self.pos + stringLen
return tostring(rString)
end
setmetatable(newpacket, {__index = packet})
return newpacket
end
receiveState = receiveStateLength
local curPacket = nil
while true do
if receiveState == receiveStateLength then
if curPacket == nil then
curPacket = createEmptyPacket()
end
local data
local buffer, status, overflow = client:receive(PACKAGE_LENGTH - curPacket.packetLenByteNum)
if buffer == nil then
if status == "closed" then
return
end
data = overflow
else
data = buffer
end
if data ~= nil then
if string.len(data) ~= 0 then
curPacket.packetLenBytes = string.pack("AA", curPacket.packetLenBytes, data)
end
end
curPacket.packetLenByteNum = string.len(curPacket.packetLenBytes)
if curPacket.packetLenByteNum == PACKAGE_LENGTH then
nextPos, curPacket.packetLen = string.unpack(curPacket.packetLenBytes, ">H")
receiveState = receiveStateContent
end
elseif receiveState == receiveStateContent then
local data
local buffer, status, overflow = client:receive(curPacket.packetLen - curPacket.packetContentByteNum)
if buffer == nil then
if status == "closed" then
return
end
data = overflow
else
data = buffer
end
if data ~= nil then
if string.len(data) ~= 0 then
curPacket.packetContentBytes = string.pack("AA", curPacket.packetContentBytes, data)
end
end
curPacket.packetContentByteNum = string.len(curPacket.packetContentBytes)
if curPacket.packetContentByteNum == curPacket.packetLen then
dispatchPacket(curPacket)
curPacket = nil
receiveState = receiveStateLength
end
end
end