用c#程序与Erlang服务器通信

用c#程序与Erlang服务器通信,c#,erlang,server,binaries,C#,Erlang,Server,Binaries,我正在尝试为我的程序编写Erlang服务器,但仍然有一些我无法处理的问题。使用此选项时(我在erlang中编写客户机来测试服务器): 看起来一切正常,但当我试图从我的c#client发送东西时,服务器看到连接和断开连接,但看不到消息(它甚至没有反应) 我意识到这可能是Erlang的问题 术语_到_二进制() 但我不知道如何修复它。我需要简单的: 客户端将数据转换为字节 客户端向服务器发送数据 服务器对数据进行编码 服务器决定做什么 服务器生成新数据,将其转换为字节并发送到客户端 客户端对其进行编

我正在尝试为我的程序编写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;
    
        }
    }