我试图为我的程序编写Erlang服务器,但仍然遇到一些我无法处理的问题。使用它时(我在erlang中编写了客户端来测试服务器):
send(Socket, Message) ->
BinMsg = term_to_binary(Message),
gen_tcp:send(Socket, Message).
一切似乎都没问题,但是当我试图从我的c#客户端发送内容时,服务器会看到连接和断开连接,但看不到消息(它甚至没有反应)
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
String foo = theLine + "\r\n";
test = System.Text.Encoding.UTF8.GetBytes(foo);
theWriter.Write(test);
我意识到这可能是Erlang的一些问题
term_to_binary()
但我不知道如何解决它。我需要简单:
我可以在字符串上做到这一点,但我不认为这种方法会很好,我想发送二进制文件而不是字符串。任何建议?
答案 0 :(得分:1)
您应该在客户端正确编码数据,以便能够在Erlang中使用term_to_binary/binary_to_term
。看一下http://erlang.org/doc/apps/erts/erl_ext_dist.html它并不难实现,我认为应该有现有的解决方案。
但是从你的话来看,你的代码看起来有些不对劲,因为Erlang应该在错误的二进制文件上抛出异常。可能与{active, true|false|once|N}
有关。您应该在socket上设置{active, true}
以便能够接收TCP数据包,因为Erlang消息(once
或N
也很好,请查看docs:http://erlang.org/doc/man/gen_tcp.html)。如果你想接收二进制文件,你应该在socket上设置binary
选项。
答案 1 :(得分:0)
所以这是我的服务器/客户端代码:
-define(TCP_OPTIONS, [binary, {packet, 2}, {active, false}, {reuseaddr, true}]).
-define(PORT, 8080).
-spec start(Port) -> pid() when
Port::integer().
start(Port) ->
process_flag(trap_exit, true),
ClientDict = dict:new(),
GamesDict = dict:new(),
HandlerPID = spawn_link(fun() -> handler(ClientDict, GamesDict) end),
imup_listener:listen(Port, HandlerPID).
%%------------------------------
% Internal Functions
%%------------------------------
handler(Clients, Games) ->
receive
{insert_client, Socket, Alias} ->
TmpClients = dict:store(Socket, Alias, Clients),
TmpClients2 = dict:store(Alias, Socket, TmpClients),
handler(TmpClients2, Games);
{get_client_id, ReceiverPID, ClientPID} ->
{ok , CID} = dict:find(ClientPID, Clients),
ReceiverPID ! {id, CID},
handler(Clients, Games);
{get_client_pid, ReceiverPID, ClientID} ->
{ok, CPID} = dict:find(ClientID, Clients),
ReceiverPID ! {pid, CPID},
handler(Clients, Games);
{host_game, HostID, GameID} ->
TmpGames = dict:append_list(GameID, [HostID], Games),
handler(Clients, TmpGames);
{add_player, PlayerID, GameID} ->
TmpGames = dict:append_list(GameID, [PlayerID], Games),
handler(Clients, TmpGames);
{get_host, ReceiverPID, GameID} ->
{ok, [HID|T]} = dict:find(GameID, Games),
{ok, HPID} = dict:find(HID, Clients),
ReceiverPID ! {host_is, HID, HPID},
handler(Clients, Games);
_ ->
{error, "I don't know what you want from me :("}
end.
监听器:
-define(TCP_OPTIONS, [binary, {packet, 2}, {active, false}, {reuseaddr, true}]).
listen(Port, HandlerPID) ->
{ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
spawn_link(fun() -> accept(LSocket, HandlerPID) end),
LSocket.
% Wait for incoming connections and spawn a process that will process incoming packets.
accept(LSocket, HandlerPID) ->
{ok, Socket} = gen_tcp:accept(LSocket),
Pid = spawn(fun() ->
io:format("Connection accepted ~n", []),
%%DictPID ! {insert, Socket, Socket},
loop(Socket, HandlerPID)
end),
gen_tcp:controlling_process(Socket, Pid),
accept(LSocket, HandlerPID).
% Echo back whatever data we receive on Socket
loop(Sock, HandlerPID) ->
inet:setopts(Sock, [{active, once}]),
receive
{tcp, Socket, Data} ->
io:format("wchodze pakiet"),
io:format("Got packet: ~p == ", [Data]),
FormatedData = process_data(Socket, Data, HandlerPID),
io:format("~p~n", [FormatedData]),
convey_message(Socket, FormatedData),
loop(Socket, HandlerPID);
{tcp_closed, Socket} ->
io:format("wchodze closed"),
io:format("Socket ~p closed~n", [Socket]);
{tcp_error, Socket, Reason} ->
io:format("wchodze error"),
io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])
end.
%%------------------------------
% Internal Functions
%%------------------------------
-spec process_data(S, D, P) -> term() when
S::port(),
D::binary(),
P::pid().
process_data(Socket, Data, HandlerPID) when is_binary(Data) ->
case binary_to_term(Data) of
{send_host, GameID, Msg} ->
HandlerPID ! {get_host, self(), GameID},
receive
{host_is, _HID, HSOCK} ->
HSOCK;
_ ->
{error, nohost}
end,
Msg;
{send_all, GameID, Msg} ->
Msg;
{send_to_id, ReceiverID, Msg} ->
HandlerPID ! {get_client_pid, self(), ReceiverID},
receive
{pid, SockPID} ->
gen_tcp:send(SockPID, term_to_binary(Msg));
_ ->
{error, noid}
end,
term_to_binary({ok, delivered});
{host_game, GameID} ->
GameID;
{join_game, GameID} ->
GameID;
{start_game, GameID} ->
GameID;
{enter, SenderID} ->
HandlerPID ! {insert_client, Socket, SenderID};
Dat ->
Dat
end;
process_data(Socket, Data, DictPID) ->
Data.
convey_message(Socket, Data) when is_binary(Data) ->
gen_tcp:send(Socket, Data);
convey_message(Socket, Data) ->
gen_tcp:send(Socket, term_to_binary(Data)).
Erlang CLient(正在工作):
connect(PortNo) ->
{ok, Socket} = gen_tcp:connect("localhost", PortNo, [binary, {active, false}, {packet, 2}]),
spawn(fun() -> recv(Socket) end),
Socket.
connect(IP, PortNo) ->
{ok, Socket} = gen_tcp:connect(IP, PortNo, [binary, {active, false}, {packet, 2}]),
spawn(fun() -> recv(Socket) end),
Socket.
send(Socket, Message) ->
BinMsg = unicode:characters_to_binary(Message),
io:format(Message ++ "~n"),
io:format(BinMsg),
gen_tcp:send(Socket, BinMsg).
recv(Socket) ->
{ok, A} = gen_tcp:recv(Socket, 0),
io:format("Received: ~p~n", [A]),
recv(Socket).
disconnect(Socket) ->
gen_tcp:close(Socket).
C#客户端:
using UnityEngine;
using System;
using System.IO;
using System.Net.Sockets;
//using System.Globalization.NumberStyles;
public class NetworkController : MonoBehaviour
{
public string tekst;
public Transform nek;
public byte[] bytesW = new byte[4];
public byte[] test;
public float[] qq = new float[4];
internal Boolean socketReady = false;
TcpClient mySocket;
NetworkStream theStream;
StreamWriter theWriter;
BStreamReader theReader;
String Host = "localhost";
public Int32 Port;
void Update()
{
string receivedText = readSocket();
if (receivedText != "")
{
tekst = receivedText;
}
}
void OnGUI()
{
if (!socketReady)
{
if (GUILayout.Button("Connect"))
{
setupSocket();
writeSocket("serverStatus:");
}
}
if (GUILayout.Button("Send"))
{
writeSocket("ala");
}
if (GUILayout.Button("Close"))
{
closeSocket();
}
GUI.Label(new Rect(0, 40, 1000, 400), tekst);
if (socketReady)
{
}
}
void OnApplicationQuit()
{
closeSocket();
}
public void setupSocket()
{
try
{
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e)
{
Debug.Log("Socket error: " + e);
}
}
public void writeSocket(string theLine)
{
if (!socketReady)
return;
//byte[] foo = System.Text.Encoding.UTF8.GetBytes(theLine);
String foo = theLine + "\r\n";
Debug.Log(foo);
test = System.Text.Encoding.UTF8.GetBytes(foo);
theWriter.Write(test);
theWriter.Flush();
}
/*
public void WriteToStream(string theLine)
{
byte[] len_bytes = BitConverter.GetBytes(length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(len_bytes);
}
writer.Write(len_bytes);
writer.Write(content);
}
*/
public String readSocket()
{
if (!socketReady)
return "";
if (theStream.DataAvailable)
return theReader.ReadLine();
//return theReader.ReadToEnd();
return "";
}
public void closeSocket()
{
if (!socketReady)
return;
theWriter.Close();
theReader.Close();
mySocket.Close();
socketReady = false;
}
}
它还没有准备好,但它应该发送基本信息,但事实并非如此。正如我所说,我对Erlang很新,所以也许我做了一些愚蠢的事情