用c#程序与Erlang服务器通信
我正在尝试为我的程序编写Erlang服务器,但仍然有一些我无法处理的问题。使用此选项时(我在erlang中编写客户机来测试服务器): 看起来一切正常,但当我试图从我的c#client发送东西时,服务器看到连接和断开连接,但看不到消息(它甚至没有反应) 我意识到这可能是Erlang的问题 术语_到_二进制() 但我不知道如何修复它。我需要简单的:用c#程序与Erlang服务器通信,c#,erlang,server,binaries,C#,Erlang,Server,Binaries,我正在尝试为我的程序编写Erlang服务器,但仍然有一些我无法处理的问题。使用此选项时(我在erlang中编写客户机来测试服务器): 看起来一切正常,但当我试图从我的c#client发送东西时,服务器看到连接和断开连接,但看不到消息(它甚至没有反应) 我意识到这可能是Erlang的问题 术语_到_二进制() 但我不知道如何修复它。我需要简单的: 客户端将数据转换为字节 客户端向服务器发送数据 服务器对数据进行编码 服务器决定做什么 服务器生成新数据,将其转换为字节并发送到客户端 客户端对其进行编
我可以对字符串进行简单的处理,但我不认为这个方法是一个好的解决方案,我想发送二进制文件而不是字符串。有什么建议吗?您应该在客户端正确编码数据,以便能够在Erlang中使用
term\u to\u binary/binary\u to\u term
。看看实施起来并不难,我认为应该有现有的解决方案
但从您的话来看,您的代码似乎有其他问题,因为Erlang应该在错误的二进制文件上抛出异常。可能与
{active,true | false | once | N}
有关。您应该在套接字上设置{active,true}
,以便能够接收作为Erlang消息的TCP数据包(一旦
或N
也很好,请查看文档:)。如果您想接收二进制文件,您可能应该在socket上设置二进制
选项。下面是我的服务器/客户端代码:
-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客户端(工作):
客户:
它还没有准备好,但它应该发送基本信息,但它没有。正如我所说的,我对Erlang还很陌生,所以也许我做了一些愚蠢的事谢谢链接,但我已经读过了(可能因为我对Erlang还很陌生),它对我没有帮助。正如我所写的,当我使用用erlang编写的客户机时,一切似乎都很好,我只有在使用c#的客户机时才会遇到问题。服务器并没有抛出异常,因为正如我测试的那个样,它看起来甚至并没有接收到消息。那么我可以不编码地写吗?这会很糟糕/不专业吗?你还是需要一些序列化格式。术语_到_二进制就像,我不知道,JSON.serialize。因此,如果您在Erlang客户端中使用
term_to_binary
,在Erlang服务器中使用binary_to_term
,您可能应该在C端使用Erlang兼容序列化。也许你可以给我们看一下erlang服务器和客户端的代码?顺便说一句,如果有疑问,请使用Wireshark!我不知道erlang客户端实际上是如何工作的,因为我可以在服务器端看到term\u to\u term
,而在客户端看不到term\u to\u binary
。另外,您使用的是{packet,2}
,这意味着Erlang希望数据包的前两个字节为数据包长度,然后等待长度
字节,然后去掉2字节的头,然后发送消息。顺便说一句,您没有使用gen_server和其他OTP实践。对不起,但你最好从
-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)).
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).
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;
}
}