首页 > 解决方案 > JSON-RPC API 的 C# 客户端

问题描述

我正在尝试向与 JSON-RPC 对话的 API 发送请求。我已经使用 Curl 测试了服务器,如下所示:

> curl -v -d 'SOME_INVALID_REQUEST' http://erbium1.sytes.net:50001
 {"jsonrpc": "2.0", "error": {"code": -32700, "message": "invalid JSON"}, "id": null}

我感兴趣的一些请求是订阅,因此发送 POST 请求似乎不适合这样做,因为我不希望服务器立即回复,而是接收一个或多个通知。

我正在尝试使用 C# 与该服务器通信,但该服务器从不回复。要发送消息,我已完成以下操作:

  1. 创建了一个TcpClient
  2. 将客户端连接到服务器(erbium1.sytes.net,50001)
  3. 从连接的客户端转到NetworkStream
  4. 写入 NetworkStream 当我将这些消息发送到服务器时,读取回调函数永远不会被调用,因此我永远不会收到来自服务器的回复。如果我要将消息发送到端口 50002 (TLS) 而不是 50001,则服务器会回复一个空字符串。

我的猜测是,进行原始 TcpClient 连接不会发送带有 HTTP 标头的消息,因此服务器只是丢弃它们?如果是这样,什么是请求订阅服务器并能够接收通知的合适方式?

TcpClient 连接和 WebSocket 之间有什么区别?WebSocket 是否适合在这里使用?

下面是我的代码示例:

// State object for receiving data from remote device.
public class ReceiverState {
    public ReceiverState(NetworkStream s) {
        this.stream = s;
    }
    public NetworkStream stream;
    public const int bufferSize = 1024;
    public byte[] buffer = new byte[bufferSize];
    public AutoResetEvent receivedEvent = new AutoResetEvent(false);
}



  static AutoResetEvent received = new AutoResetEvent(false);

  public static void PingServer(NetworkStream stream) {
      if (stream.CanWrite) {
          try {
              String rpc = "INVALID_REQUEST";
              Byte[] data = System.Text.Encoding.UTF8.GetBytes(rpc);
              stream.Write(data, 0, data.Length);
              stream.Flush();
              Console.WriteLine("Pinging...");
          } catch (Exception e) {
              Console.WriteLine(e.ToString());
          }
      } else {
          // TODO Throw an exception
          Console.WriteLine("Unable to write to stream");
      }
  }

  public static void BeginAsyncRead(NetworkStream stream, ReceiverState readState) {
      if (stream.CanRead) {
          try {
              stream.BeginRead(readState.buffer, 0, 1024,
                               new AsyncCallback(readCallBack),
                               readState);
          }
          catch (Exception e) {
              Console.WriteLine(e.ToString());
          }
      } else {
          // TODO Throw an exception
          Console.WriteLine("Unable to read from stream");
      }
  }

  private static void readCallBack(System.IAsyncResult ar) {
      // Get the state from AsyncResult
      ReceiverState state = (ReceiverState) ar.AsyncState;

      if(ar.IsCompleted){
          Int32 numBytes = state.stream.EndRead(ar);
          Console.WriteLine("Received : ");
          Console.WriteLine(Encoding.ASCII.GetString(state.buffer,0,numBytes+10));
          state.receivedEvent.Set();
      }
  }

  private static void synchronousRead(NetworkStream myNetworkStream) {
      if(myNetworkStream.CanRead){
          byte[] myReadBuffer = new byte[1024];
          StringBuilder myCompleteMessage = new StringBuilder();
          int numberOfBytesRead = 0;

          // Incoming message may be larger than the buffer size.
          do{
              numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
              myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
          }
          while(myNetworkStream.DataAvailable);
          // Print out the received message to the console.
          Console.WriteLine("You received the following message : " +
                            myCompleteMessage);
      }
      else{
          Console.WriteLine("Sorry.  You cannot read from this NetworkStream.");
      }
  }

  public static void Main(string[] args) {
    // Create a new TcpClient
    TcpClient client = new TcpClient();
    Console.WriteLine("Connecting...");
    client.Connect("electrum3.hachre.de", 50001);
    NetworkStream stream = client.GetStream();
    Stream inStream = new MemoryStream();
    ReceiverState readState = new ReceiverState(stream);
    readState.receivedEvent = received;
    BeginAsyncRead(stream, readState);
    PingServer(stream);
    received.WaitOne();
  }

标签: c#.nettcpwebsocketrpc

解决方案


推荐阅读