C# Client for JSON-RPC API - c#

I'm trying to send requests to an API that talks JSON-RPC. I've tested the server with Curl as such:
> curl -v -d 'SOME_INVALID_REQUEST' http://erbium1.sytes.net:50001
{"jsonrpc": "2.0", "error": {"code": -32700, "message": "invalid JSON"}, "id": null}
Some of the requests that interest me are subscriptions, thus sending POST requests seem unfit for this because I don't expect the server to reply instantly, rather receive one or more notifications.
I'm trying to talk to this server using C#, but the server never replies. To send the messages I've done the following :
Created a TcpClient
Connected the client to the server (erbium1.sytes.net,50001)
Go a NetworkStream from the connected client
Wrote to the NetworkStream
When I send these messages to the server, the read callback function is never invoked thus I am never receiving replies from the server. If I were to send the messages to port 50002 (TLS) instead of 50001, the server replies with an empty string.
My guess is, doing a raw TcpClient connection does not send the messages with the HTTP headers thus the server is just dropping them? If so, what would be a suitable way of requesting subscriptions to the server and be able to receive notifications?
What would be the difference between a TcpClient connection and a WebSocket? Would WebSocket be the suitable thing to use here?
Below a sample of my code :
// 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();
}

Related

TcpListener Client stays connected sending multiple messages but server only receives or processes the first message

I am setting up a server to read some network clients using TcpListener. The Client sends some data I verify that data and send a response to that data, the client stays connected and sends a second response and I verify that data and send a response back, its like logging in to the server twice. The first login get sent back to the client just fine but the second time the client responds the server does not show that it received anymore data from the client.
I have tested it by setting up a dummy client (the real client is Cell phone based ODB2). With the dummy client set up I did verify that the first handshake happens but the when the client sends the second set of text it does not show up on the server.
class Program
{
static private TcpListener listener = null;
static private TcpClient client = null;
static private NetworkStream stream = null;
static private int iCount = 0;
static Int32 port = 8090;
static IPAddress localAddr = IPAddress.Parse("192.168.1.17");
static void Main(string[] args)
{
listener = new TcpListener(localAddr, port);
listener.Start();
while (true)
{
try
{
client = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ThreadProc, client);
}
catch (IOException ioex)
{
RestartStream();
}
}
}
private static void ThreadProc(object obj)
{
var client = (TcpClient)obj;
Byte[] bytes = new Byte[client.ReceiveBufferSize];
stream = client.GetStream();
try
{
int bytesRead = stream.Read(bytes, 0, (int)client.ReceiveBufferSize);
string returndata = Encoding.ASCII.GetString(bytes, 0, bytesRead).Replace("-", "");
byte[] sendBytes;
if (returndata.ToLower().StartsWith("7e") && returndata.ToLower().EndsWith("7e"))
{
//… do stuff with the data and send it back to the client
sendBytes = Encoding.Default.GetBytes(login1);
stream.Write(sendBytes, 0, sendBytes.Length);
stream.Flush();
}
else
{
SaveStream(returndata);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Test Client Code:
//---data to send to the server---
string textToSend = "7E010000360141850000080000000000000000000000000000000000000000000000000000000000000035303030303038003131313131313131313131313131313131F67E";
//---create a TCPClient object at the IP and port no.---
TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
NetworkStream nwStream = client.GetStream();
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(textToSend);
//---send the text---
Console.WriteLine("Sending : " + textToSend);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
Console.WriteLine("Received : " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
string Text2 = "7E0100003601418535303030303038003131313131313131313131313131313131F67E";
Console.WriteLine("Sending : " + Text2);
byte[] bytesToSend2 = ASCIIEncoding.ASCII.GetBytes(Text2);
nwStream.Write(bytesToSend2, 0, bytesToSend2.Length);
client.Close();
Console.ReadLine();
What I need to happen is my understanding is the client stays connected the whole time and send data over and over, my system seems to accept it once and then stops receiving it, I need it to continue to receive the client data and process it.
Ok so I figured it out, there should be a second while loop in side the thread.
static void Main(string[] args)
{
listener = new TcpListener(localAddr, port);
var clientSocket = default(TcpClient);
listener.Start();
var counter = 0;
while (true)
{
clientSocket = listener.AcceptTcpClient();
var client = new ConnectedDevice();
client.startClient(clientSocket, counter.ToString(), sqlConnString);
}
}
ConnectedDevice class:
class ConnectedDevice
{
private TcpClient _clientSocket;
private string _clientNumber;
private string _sqlConnString;
public void startClient(TcpClient clientSocket, string clientNumber, string sqlConnString)
{
_clientSocket = clientSocket;
_clientNumber = clientNumber;
_sqlConnString = sqlConnString;
var ctThread = new Thread(ProcessClient);
ctThread.Start();
}
private void ProcessClient()
{
while (_clientSocket.Connected)
{
try
{
Byte[] bytes = new Byte[_clientSocket.ReceiveBufferSize];
var networkStream = _clientSocket.GetStream();
networkStream.ReadTimeout = 10000;
int i;
while ((i = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
var data = System.Text.Encoding.ASCII.GetString(bytes, 0, i).Replace("-", "");
byte[] sendBytes;
Console.WriteLine(data);
string sLogin1 = "7E81000013014185000008000000000054523230313731303138303930303137497E";
sendBytes = Encoding.ASCII.GetBytes(sLogin1);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
}
catch (Exception ex)
{
}
}
}
}

Very basic web server in C#

I'm wanting to run a little socket server in C# to be accessed by a browser. I have a socket listener up and running on a specific port, and am trying to access it via the browser:
class WebSocketServer
{
private static string output = string.Empty;
public void CreateListener()
{
TcpListener tcpListener = null;
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
tcpListener = new TcpListener(ipAddress, 1313);
tcpListener.Start();
output = "Waiting for a connection";
}
catch (Exception e)
{
throw;
}
var socketHelper = new SocketHelper();
while (true)
{
Thread.Sleep(10);
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[256];
var stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
socketHelper.ProcessMessage(tcpClient, stream, bytes);
}
}
}
class SocketHelper
{
private static int counter = 0;
public void ProcessMessage(TcpClient tcpClient, NetworkStream stream, byte[] bytesReceived)
{
// handle message received and send response to client
var msg = Encoding.ASCII.GetString(bytesReceived);
string response = string.Empty;
if (msg.Substring(0, 10) == "GET / HTTP")
{
response = "";// html page
}
byte[] bytesToSend = Encoding.ASCII.GetBytes(response);
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
The browser appears to connect to it, but it never seems to display the html - what's wrong? I'm eventually wanting to be able to serve up JSON data via a REST interface. In addition, is there a much easier solution to (I assume) this common problem.

TcpClient not reading whenever new data is available

I'm trying to create a program that listens to my server via a TCP Socket so it can be notified. For example, if I update the price of an item, all clients connected to the TCP Server gets sent a JSON string telling them so. The idea is that my C# program maintains this TCP Socket throughout run time, reading from the socket whenever there is new data.
My problem is that TcpClient is refusing to read past the first round of bytes being sent. It reads that and then just stops working altogether. Code is as follows:
TcpClient _client;
static int readBytesLength = 1024;
Byte[] readBytes = new byte[readBytesLength];
private void initClientConnection() {
_client = new TcpClient();
_client.BeginConnect(SERVER_IP, SERVER_PORT, new AsyncCallback(connectCallback), _client);
}
private void connectCallback(IAsyncResult result) {
if (_client.Connected) {
Console.WriteLine("Connected!");
this.beginReading();
}
else {
Console.WriteLine("Failed to connect, trying again!");
this.initClientConnection();
}
}
private void beginReading() {
readBytes = new byte[readBytesLength];
_client.GetStream().BeginRead(readBytes, 0, readBytesLength, receiveCallback, _client.GetStream());
}
private void receiveCallback(IAsyncResult result) {
Console.WriteLine("Read Callback!");
if (_client.GetStream().CanRead) {
string response = Encoding.UTF8.GetString(readBytes);
Console.WriteLine("Stream got \n{0}", response);
}
this.beginReading();
}
Again, I only receive 1 batch data and it just stops receiving.
Stream got
-----Received-----
{"status":"SUCCESS","message": "Log in confirmed (2)"}
There are still a few weird things going on in your code. There's no reason to use Stream.CanRead where you are using it, and you aren't using the correct overload of Encoding.GetString. I've cleaned up your example a bit and fixed some oddities/unnecessary bits.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class TcpConnection
{
private const int BUF_SIZE = 1024;
private readonly byte[] buffer = new byte[BUF_SIZE];
private readonly TcpClient client = new TcpClient();
public void Start(IPAddress ip, int port)
{
client.BeginConnect(ip, port, ConnectCallback, null);
}
private void ConnectCallback(IAsyncResult result)
{
client.EndConnect(result);
Console.WriteLine("Connected!");
}
private void StartRead()
{
if(!client.Connected)
{
Console.WriteLine("Disconnected, can't read.");
return;
}
NetworkStream stream = client.GetStream();
stream.BeginRead(buffer, 0, BUF_SIZE, ReadCallback, stream);
}
private void ReadCallback(IAsyncResult result)
{
NetworkStream stream = (NetworkStream)result.AsyncState;
int bytesRead = stream.EndRead(result);
Console.WriteLine("Read Callback!");
if (bytesRead > 0)
{
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Stream got \n{0}", response);
}
StartRead();
}
}

EndRead throws IO exception

This is for local communication between a MoSync application and an external DLL, MoSync does not allow me to use 3rd part DLLs and that is the reason why I have to implement this bridge software instead of using a simple call to a DLL, I have to convert from xml to the DLL Message format, and again to XML. I know this is a dumb thing, unfortunately there is no flexibility to change the architecture. Initially i thought that there was only one request so I had Sync coms but now I find out there can be more than one request, so I need to implement Async back again.
I have an exception that is thrown from time to time, since I am new to C# I am unable to find the memory leak... perhaps a pair of more well trained eyes can find the issue
SOURCE CODE:
I have written the following code, I am quite new to C# and Sockets, so perhaps I have made some big mistakes that only more experienced eyes can detect. This is to be used in a Windows Mobile 6.1 device, so I am trying to avoid using many threads.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Diagnostics;
namespace SmartDevice_Server
{
//ClientConnection saves connection information is used to keep context in Async and Event calls
public class ClientConnection : EventArgs
{
public NetworkStream NetworkStream { get; private set; }
public byte[] Data { get; private set; }
public int byteReadCount { get; set; }
public ClientConnection(NetworkStream networkStream, byte[] data)
{
NetworkStream = networkStream;
Data = data;
}
}
//MySocket - Is a server that listens for events and triggers Events upon Request Completion
public class MySocketTCP
{
#region Class Members
TcpListener myTcpListener;
TcpClient myTcpClient;
NetworkStream myNetworkStream;
const string localHost = "127.0.0.1";
IPAddress myAddress = IPAddress.Parse(localHost);
int myPortNumber = 58889;
byte[] myData;
int bytesReadCount;
const int MIN_REQUEST_STRING_SIZE = 10;
int TimeStart;
//Event
public event socketReadCompleteHandler socketReadCompleteEvent;
public EventArgs eventArguments = null;
public delegate void socketReadCompleteHandler(MySocketTCP myTcpSocket, ClientConnection eventArguments);
#endregion
//Constructor
public MySocketTCP()
{
Init();
}
//Constructor overloaded to receive IPAdress Host, and Port number
public MySocketTCP(IPAddress hostAddress, int portNumber)
{
myAddress = hostAddress;
myPortNumber = portNumber;
Init();
}
//Initializes the TCPListner
public void Init()
{
try
{
myTcpListener = new TcpListener(myAddress, myPortNumber);
//myNetworkStream = myTcpClient.GetStream();
}
catch (Exception ex)
{
throw ex;
}
}
/*TODO_Listener_Timer: After you accept a connection you wait for data to be Read indefinitely
*Possible solution: Use a timeout to close the socket connection.
*Check WIKI, TODOS
* */
//Listens Asynchronously to Clients, class a recieveMessageHandler to process the read
public void ListenAsync()
{
myTcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
myTcpClient = myTcpListener.AcceptTcpClient();
var client = new ClientConnection(myTcpClient.GetStream(), new byte[myTcpClient.ReceiveBufferSize]);
// Capture the specific client and pass it to the receive handler
client.NetworkStream.BeginRead(client.Data, 0, client.Data.Length, r => receiveMessageHandler(r, client), null);
}
}
//Callback is used to Process the request Asynchronously, triggers socketReadCompleteEvent
public void receiveMessageHandler(IAsyncResult asyncResult, ClientConnection clientInstance)
{
bytesReadCount = 0;
lock (clientInstance.NetworkStream)
{
try
{
bytesReadCount = clientInstance.NetworkStream.EndRead(asyncResult);
clientInstance.byteReadCount = bytesReadCount;
}
catch (Exception exc)
{
throw exc;
}
}
if (bytesReadCount < MIN_REQUEST_STRING_SIZE)
{
//Could not read form client.
Debug.WriteLine("NO DATA READ");
}
else
{
if (socketReadCompleteEvent != null)
{
socketReadCompleteEvent(this, clientInstance);
}
}
}
//Reads the request, uses the ClientConnection for context
public string ReadAsync(ClientConnection connObj)
{
int bytesReadCount = connObj.byteReadCount;
byte[] myData = connObj.Data;
string xmlMessage;
try
{
xmlMessage = Encoding.ASCII.GetString(myData, 0, bytesReadCount);
}
catch (Exception ex)
{
throw ex;
}
return xmlMessage;
}
//Deprecated
public string Read()
{
string xmlMessage;
try
{
xmlMessage = Encoding.ASCII.GetString(myData, 0, bytesReadCount);
}
catch (Exception ex)
{
throw ex;
}
return xmlMessage;
}
//Deprecated
public void Write(byte[] outBytes)
{
try
{
myNetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
}
//Deprecated
public void Write(string outMessage)
{
byte[] outBytes = Encoding.ASCII.GetBytes(outMessage);
try
{
myNetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
int TimeEnd = Environment.TickCount;
int TimeResult = TimeEnd - TimeStart;
}
//Is used to send the message to the correct socket
public void WriteAsync(ClientConnection connObj, string outMessage)
{
byte[] outBytes = Encoding.ASCII.GetBytes(outMessage);
try
{
connObj.NetworkStream.Write(outBytes, 0, outBytes.Length);
}
catch (Exception ex)
{
throw ex;
}
int TimeEnd = Environment.TickCount;
int TimeResult = TimeEnd - TimeStart;
}
//Closes the client
public void Close()
{
//myNetworkStream.Close();
try
{
myTcpClient.Close();
}
catch (Exception ex)
{
throw ex;
}
}
}
}
The most likely problem is that you are expecting to do exactly three "reads" for the three "writes" that client did.
This is a wrong assumption since TCP socket is a byte stream and does not preserve your application message boundaries. The server might consume those three "messages" sent by the client in one, or two, or seventeen reads.
You need to tell the server somehow where the message ends in the byte stream. Usual choices are fixed length messages, delimiters, message headers that tell length of the payload, self-describing formals like XML, etc.
So you continue reading from the stream until you have a complete message for processing, but at the same time you might have a part of the next message already read into your buffer.
I think the problem here is that you're only holding a single NetworkStream (myNetworkStream) as such, if a second client connects before the first has sent data, your accept loop will overwrite myNetworkStream with the stream for the 2nd connection. When the first client then sends some data your receiveMessageHandler will call EndRead on the 2nd connection's NetworkStream (which was stored in myNetworkStream when the 2nd client connected), but passing in the asyncResult from the 1st client's read. This causes the exception you indicate. Specifically when I tested it, I got the following message:
Unable to read data from the transport connection: The IAsyncResult object was not returned from the corresponding asynchronous method on this class.
Parameter name: asyncResult.
Try making the following changes:
// Create a class to hold details related to a client connection
public class ClientConnection
{
public ClientConnection(NetworkStream networkStream, byte[] data)
{
NetworkStream = networkStream;
Data = data;
}
public NetworkStream NetworkStream { get; private set; }
public byte[] Data { get; private set; }
}
public void Listen()
{
myTcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
myTcpClient = myTcpListener.AcceptTcpClient();
var client = new ClientConnection(myTcpClient.GetStream(), new byte[myTcpClient.ReceiveBufferSize]);
// Capture the specific client and pass it to the receive handler
client.NetworkStream.BeginRead(client.Data, 0, client.Data.Length, r => receiveMessageHandler(r, client), null);
}
}
public void receiveMessageHandler(IAsyncResult asyncResult, ClientConnection client)
{
var byteReadCount = client.NetworkStream.EndRead(asyncResult);
if (byteReadCount < MIN_REQUEST_STRING_SIZE)
{
//Could not read form client.
//Erro - Como tratar? Close()
}
else
{
if (socketReadCompleteEvent != null)
{
socketReadCompleteEvent(this, eventArguments);
}
}
}
As others have mentioned, there are additional issues related to your expectations of matched reads/writes between sender and receiver, but this seems to be the cause of the actual issue you're seeing.
Edit:
Here's a server that will receive data, and call a callback method when a full message is received. The callback returns a string, which is then sent back to the client, which calls its own replyCallback with the response data. Only a single request-response is sent per connection (which is rather inefficient, but should serve as a good starting point).
public static class Server
{
public static void Run(int port, Action<string> callback)
{
var listener = new TcpListener(IPAddress.Loopback, port);
listener.Start();
while (true)
{
using (var client = listener.AcceptTcpClient())
{
try
{
var buffer = new byte[2048];
using (var memoryStream = new MemoryStream())
{
using (var stream = client.GetStream())
{
stream.ReadTimeout = 1000; // 1 second timeout
int bytesRead;
// Loop until Read returns 0, signalling the socket has been closed
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
}
// Pass the client's message to the callback and use the response as the reply message to the client.
var reply = Encoding.UTF8.GetBytes(callback(Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length)));
stream.Write(reply, 0, reply.Length);
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
}
}
}
}
Here's a small client program that will connect, send its data and wait for a response. Once the response is received, it will pass call replyCallback with the server's response:
public static class Client
{
public static void Run(string hostname, int port, string dataToSend, Action<string> replyCallback)
{
using (var client = new TcpClient(hostname, port))
{
using (var stream = client.GetStream())
{
var buffer = Encoding.UTF8.GetBytes(dataToSend);
stream.Write(buffer, 0, buffer.Length);
// Shutdown the send side of the socket, indicating to the server we're done sending our message
client.Client.Shutdown(SocketShutdown.Send);
using (var memoryStream = new MemoryStream())
{
stream.ReadTimeout = 1000; // 1 second timeout
int bytesRead;
// Loop until Read returns 0, signalling the socket has been closed
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
replyCallback(Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length));
}
}
}
}
}
And a small test-harness to tie it all together:
static class Program
{
static void Main(string[] args)
{
var port = 12345;
ThreadPool.QueueUserWorkItem(o => Server.Run(port, ProcessClientMessage));
while (true)
{
Console.WriteLine("Enter a message to send and hit enter (or a blank line to exit)");
var data = Console.ReadLine();
if (string.IsNullOrEmpty(data)) break;
Client.Run("localhost", port, data, m => Console.WriteLine("Client received server reply: {0}", m));
}
}
private static string ProcessClientMessage(string clientMessage)
{
Console.WriteLine("Server received client message: {0}", clientMessage);
// This callback would ordinarily process the client message, then return a string that will be sent back to the client in response.
// For now, we'll just return a fixed string value...
return "This is the server reply...";
}
}

HTTP GET (with Header 'Connection: keep alive') over TCP

I want to do the following with a raw C# socket. I understand that usually the most appropriate way is via HTTP, with a HTTP client. The browser understands that this connection must be kept open in some way.
http://server.domain.com/protocol/do_something.txt
I am trying the following in C#, but have had no luck. What am I doing wrong? Is there a header missing? Should I be encoding what I'm sending to the server in some way? For the ReceiverSocket client, I'm using the following code, but it's just a very standard asynchronous socket client: https://stackoverflow.com/a/10390066/971580
ReceiverSocket socket = new ReceiverSocket("server.domain.com", 80);
socket.Connect();
System.Threading.Thread.Sleep(1000);
String message = "GET /protocol/do_something.txt HTTP/1.1";
message += "\r\n";
message += "\r\n";
socket.Send(message);
The socket can connect successfully, but I don't get any response when I send anything to the server. This is how I am connecting, sending and receiving.t (Apologies: I tried to do this in snippets, rather than including all the methods, but it looked horrid. . .)
public ReceiverSocket(String address, int port) : base(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
messageQueue = new Queue<MessageBase>();
IPHostEntry ipHostInfo = Dns.GetHostEntry(address);
IPAddress ipAddress = ipHostInfo.AddressList[0];
remoteEP = new IPEndPoint(ipAddress, port);
}
public void Connect()
{
this.BeginConnect(remoteEP, ConnectCallback, this);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (client.Connected)
{
client.EndConnect(ar);
Console.WriteLine("Connect Callback - Connected");
StateObject state = new StateObject();
state.workSocket = client;
state.BufferSize = 8192;
if (SocketConnected != null)
SocketConnected(client);
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state);
}
else
{
Thread.Sleep(5000);
Connect();
}
}
catch (Exception ex)
{
Reconnect();
}
}
private void ReceiveCallback(IAsyncResult ar)
{
Console.WriteLine("Never gets here. . . ");
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
foreach (MessageBase msg in MessageBase.Receive(client, bytesRead, state))
{
// Add objects to the message queue
lock (this.messageQueue)
this.messageQueue.Enqueue(msg);
}
if (DataRecieved != null)
DataRecieved(client, null);
client.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0, ReceiveCallback, state);
}
else
{
Reconnect();
}
}
catch (SocketException)
{
Reconnect();
}
}
public void Send(String msg)
{
try
{
byte[] bytes = GetBytes(msg);
if (this.Connected)
{
Console.WriteLine("Sending: " + msg);
this.BeginSend(bytes, 0, bytes.Length, 0, SendCallback, this);
}
else
{
Reconnect();
}
}
catch (SocketException sox)
{
Reconnect();
}
catch (Exception ex)
{
int i = 0;
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
}
public class StateObject
{
public Socket workSocket = null;
public int readOffset = 0;
public StringBuilder sb = new StringBuilder();
private int bufferSize = 0;
public int BufferSize
{
set
{
this.bufferSize = value;
buffer = new byte[this.bufferSize];
}
get { return this.bufferSize; }
}
private byte[] buffer = null;
public byte[] Buffer
{
get { return this.buffer; }
}
}
Shouldn't the fact that I haven't included the message += "Connection: close" header mean that the socket should just start sending whatever data it has asynchronously? Just to note also: I can connect successfuly using Telnet and send the data, just not with a socket yet!
Any pointers at all would be appreciated.
Thanks.
Do NOT call Send() until ConnectCallback() is called first, otherwise you risk sending your data prematurely. Using Sleep() to wait for the connection is wrong.
Do NOT call BeginReceive() until after Send() has finished sending the data.
Because you are using HTTP 1.1, then yes, the connection is kept alive by default if you are connecting to an HTTP 1.1 server. The server's Connection response header will indicate whether the server is actually keeping the connection open or not.
Also, as stated by someone else, HTTP 1.1 requests MUST have a Host header or else the request is malformed and can be rejected/ignored by the server. HTTP 1.1 has a notion of virtual hosts running on the same IP, so the Host header tells the server which host the client wants to talk to.

Categories

Resources