I am writing a socket listener and testing it with SocketTest, and it only reads when a breakpoint is set. It connects with or without the breakpoint. I tried added a sleep in the while (infinite because it's on it's own thread).
With a breakpoint, it works perfectly every time, which makes me think it's a timing or buffer issue of some sort, and I could use some help pinpointing the cause. The exception blocks are empty (I just wrote the code) and will be added to, but they do not catch so it's not an exception issue. Here is the code:
public static void doSocket()
{
TcpListener serverSocket = new TcpListener(Globals.foxProAddress, Globals.foxProPort);
TcpClient clientSocket = default(TcpClient);
try
{
serverSocket.Start();
}
catch (Exception e) { }
clientSocket = serverSocket.AcceptTcpClient();
while (true)
{
try
{
NetworkStream networkStream = clientSocket.GetStream();
byte[] bytesFrom = new byte[100025];
networkStream.Read(bytesFrom, 0, bytesFrom.Length);
string dataFromFoxPro = System.Text.Encoding.ASCII.GetString(bytesFrom);
if (!dataFromFoxPro.Equals(""))
{
Payments.startTransaction(dataFromFoxPro);
}
}
catch (Exception e) { }
}
}
Check the return value of Read() [MSDN]:
If no data is available for reading, the Read method returns 0.
With a breakpoint set, it it more likely that data arrives in the meanwhile.
You should also pass the index (0) and the number of bytes read into GetString() [MSDN].
I'd also move the clientSocket.GetStream(); outside the loop, just to make clear to the reader that you want to keep the stream during the whole loop. Otherwise someone could think that there's a Dispose() missing, which would destroy the stream.
Here's a quick example of what John Gardner suggests:
public static void doSocket()
{
try
{
TcpListener serverSocket = new TcpListener(Globals.foxProAddress, Globals.foxProPort);
serverSocket.Start();
TcpClient clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
int bytesRead;
string buffer = "";
byte[] bytesFrom = new byte[4096];
while (true)
{
bytesRead = networkStream.Read(bytesFrom, 0, bytesFrom.Length);
string dataFromFoxPro = System.Text.Encoding.ASCII.GetString(bytesFrom, 0, bytesRead);
buffer = buffer + dataFromFoxPro;
// look at buffer and see if it has one or more complete "messages":
while (buffer.Contains("something")) // made up protocol
{
string msg = buffer.Substring(0, buffer.IndexOf("something")); // extract the message <-- completely made up
buffer = buffer.Remove(0, msg.Length); // remove the msg from the beginning of the buffer <-- pseudo-code!
Payments.startTransaction(msg);
}
}
}
catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
This is very rough code and is simply designed to give an overview of what the code might look like.
Related
I have implemented a socket client using TcpClient class. So I can send and receive data, everything works good. But I ask some of the guru's out there :) Is there something wrong with my implementation? maybe there is a better way of doing things. In particular, how do I handle disconnects? Is there some indicator (or maybe I can write one myself) that tells me that socket has disconnected?
I also have looked into async await features of Socket class, but can't wrap my head around "SocketAsyncEventArgs", why is it there in the first place.
Why cant i just: await Client.SendAsync("data"); ?
public class Client
{
private TcpClient tcpClient;
public void Initialize(string ip, int port)
{
try
{
tcpClient = new TcpClient(ip, port);
if (tcpClient.Connected)
Console.WriteLine("Connected to: {0}:{1}", ip, port);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Initialize(ip, port);
}
}
public void BeginRead()
{
var buffer = new byte[4096];
var ns = tcpClient.GetStream();
ns.BeginRead(buffer, 0, buffer.Length, EndRead, buffer);
}
public void EndRead(IAsyncResult result)
{
var buffer = (byte[])result.AsyncState;
var ns = tcpClient.GetStream();
var bytesAvailable = ns.EndRead(result);
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytesAvailable));
BeginRead();
}
public void BeginSend(string xml)
{
var bytes = Encoding.ASCII.GetBytes(xml);
var ns = tcpClient.GetStream();
ns.BeginWrite(bytes, 0, bytes.Length, EndSend, bytes);
}
public void EndSend(IAsyncResult result)
{
var bytes = (byte[])result.AsyncState;
Console.WriteLine("Sent {0} bytes to server.", bytes.Length);
Console.WriteLine("Sent: {0}", Encoding.ASCII.GetString(bytes));
}
}
And the usage:
static void Main(string[] args)
{
var client = new Client();
client.Initialize("127.0.0.1", 8778);
client.BeginRead();
client.BeginSend("<Names><Name>John</Name></Names>");
Console.ReadLine();
}
Okay it took me 10 seconds to find biggest issue you could've done :
public void BeginRead()
{
var buffer = new byte[4096];
var ns = tcpClient.GetStream();
ns.BeginRead(buffer, 0, buffer.Length, EndRead, buffer);
}
But don't worry that's why we are on SO.
First let me explain why it's such a big issue.
Assume that you're sending message which is 4097 bytes long. Your buffer can only accept 4096 bytes meaning that you cannot pack whole message into this buffer.
Assume you're sending message which is 12 bytes long. You're still allocating 4096 bytes in your memory just to store 12 bytes.
How to deal with this?
Every time you work with networking you should consider making some kind of protocol ( some people call it message framing, but it's just a protocol ) that will help you to identify incomming package.
Example of a protocol could be :
[1B = type of message][4B = length][XB = message]
- where X == BitConvert.ToInt32(length);
Receiver:
byte messageType = (byte)netStream.ReadByte();
byte[] lengthBuffer = new byte[sizeof(int)];
int recv = netStream.Read(lengthBuffer, 0, lengthBuffer.Length);
if(recv == sizeof(int))
{
int messageLen = BitConverter.ToInt32(lengthBuffer, 0);
byte[] messageBuffer = new byte[messageLen];
recv = netStream.Read(messageBuffer, 0, messageBuffer.Length);
if(recv == messageLen)
{
// messageBuffer contains your whole message ...
}
}
Sender:
byte messageType = (1 << 3); // assume that 0000 1000 would be XML
byte[] message = Encoding.ASCII.GetBytes(xml);
byte[] length = BitConverter.GetBytes(message.Length);
byte[] buffer = new byte[sizeof(int) + message.Length + 1];
buffer[0] = messageType;
for(int i = 0; i < sizeof(int); i++)
{
buffer[i + 1] = length[i];
}
for(int i = 0; i < message.Length; i++)
{
buffer[i + 1 + sizeof(int)] = message[i];
}
netStream.Write(buffer);
Rest of your code looks okay. But in my opinion using asynchronous operations in your case is just useless. You can do the same with synchronous calls.
It's hard to answer because theres no exact question here but more some kind of code review. But still some hints:
Your connect mechanism seems wrong. I don't think TcpClient.Connected will block until the connection was established. So it will often just fail as the connection is in progress and then you start all over again. You should switch to using a blocking or async Connect method.
SocketAsyncEventArgs is a mechanism for high performance async data transmission. There's rarely a need for it. You should just ignore it
If you want to send data asynchronously you should use the Async methods which return a Task, because these can be easily combined with async/await.
The APM model (BeginXYZ/EndXYZ) is kind of deprecated, you shouldn't use it anymore in new code. One issue with it is that sometimes the End method is called synchronously inside the Begin method which can lead to surprising behavior. If this is not the case the completion callback will be performed from a random thread on the ThreadPool. This is also often not what you want. The TPL methods avoid this.
For your simple use case the blocking methods are also totally fine and do not come with the complexity of the various async methods.
The reading side of the code with TPL methods (untested):
public async Task Initialize(string ip, int port)
{
tcpClient = new TcpClient;
await tcpClient.ConnectAsync(ip, port);
Console.WriteLine("Connected to: {0}:{1}", ip, port);
}
public async Task Read()
{
var buffer = new byte[4096];
var ns = tcpClient.GetStream();
while (true)
{
var bytesRead = await ns.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) return; // Stream was closed
Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, bytesRead));
}
}
In the initialization part you would do:
await client.Initialize(ip, port);
// Start reading task
Task.Run(() => client.Read());
For using synchronous methods delete all Async occurences and replace Task with Thread.
I'm trying to use lua script to extract some data from a program, and then send that data to a c# script which then processed it and returns some simple messages for the lua script to then pass along to the program.
The lua script is as follows
-- Socket decls
local socket = require("socket")
local host, port = "127.0.0.1", 3000
local tcp = assert(socket.tcp())
tcp:connect(host,port)
tcp:settimeout(0)
tcp:send("Stream starting...")
function sendEventInfoToServer(string)
tcp:send(string)
end
function processEventInfo()
local received, status = tcp:receive()
if received ~= nil then
print(received, status);
end
end
while true do
-- unrelated logic
processEventInfo();
end
and on the C# end
public class SimpleTCPListener
{
private TcpListener tcpListener;
private TcpClient _tcpClient;
private Thread listenThread;
private NetworkStream clientStream;
List<string> eventsWaiting;
public List<string> EventsWaiting {
get {
List<string> tempList = new List<string>();
for (int i = 0; i < eventsWaiting.Count; i++)
tempList.Add(eventsWaiting[i]);
EventsWaiting = new List<string>();
return tempList;
}
private set { eventsWaiting = value; }
}
public SimpleTCPListener()
{
EventsWaiting = new List<string>();
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while(true)
{
// blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
// create a thread to handle communication
// with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCom));
clientThread.Start(client);
clientStream = client.GetStream();
}
}
public void SendSavestateLoadRequest()
{
if(clientStream != null)
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("HelloLua!\n");
Console.WriteLine("Sending data back to lua");
if (clientStream.CanWrite)
clientStream.Write(buffer, 0, buffer.Length);
else
Console.WriteLine("Connection close!");
//clientStream.Flush();
}
}
private void HandleClientCom(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while(true)
{
bytesRead = 0;
try
{
// blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
// a socket error has occured
break;
}
if(bytesRead == 0)
{
// the client disconnected
break;
}
// message has been recieved
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
string s = encoder.GetString(message, 0, bytesRead);
Console.WriteLine(s);
if (!string.IsNullOrEmpty(s))
eventsWaiting.Add(s);
}
tcpClient.Close();
}
}
Now, the Lua talks to the C# thread no problem, and the C# doesn't report any errors when sending data back to the lua, but on the lua side it's constantly receiving nil, however if I remove the nil check it sometimes receives and prints the string, but with the nil check it never seems to find 'received' as not nil. I'm really new with lua script so hopefully it's something simple I'm not understanding about the syntax but I can't seem to find lot of documentation.
Any suggestions would be hugely appreciated.
I am in need of a C# layer which will help to exchange the data between two TCP ports which are listening.
For example, There is a listener port # 192.168.1.2::5555 and another listener port # 192.168.1.4::6666.
I am able to establish the connection to both the listeners using socket.connect
I am getting confused during creation of 2 threads
1> Sock1.read()->convert to bytes ->sock2 .write()
2> Sock2.read()->Convert to bytes -> Sock1.write()
I think this is entering into the infinite loop. Is there any better way of exchanging packets between 2 Listening ports by establishing connection to both ports?
I have to implement a method
Private void ExchangePackets(IpEndpoint ipe1,IpEndpoint ipe2)
{
//code here
}
It can be something like this:(Not tested)
void ExchangePackets(IPEndPoint ipe1, IPEndPoint ipe2)
{
TcpClient tcp1 = new TcpClient();
tcp1.Connect(ipe1);
TcpClient tcp2 = new TcpClient();
tcp2.Connect(ipe2);
Task.Factory.StartNew(() => ByPass(tcp1, tcp2), TaskCreationOptions.LongRunning);
Task.Factory.StartNew(() => ByPass(tcp2, tcp1), TaskCreationOptions.LongRunning);
}
void ByPass(TcpClient tcp1, TcpClient tcp2)
{
using (tcp1)
using (tcp2)
{
Stream s1 = tcp1.GetStream();
Stream s2 = tcp2.GetStream();
byte[] buf = new byte[0x10000];
int len = s1.Read(buf, 0, buf.Length);
while (len > 0)
{
s2.Write(buf, 0, len);
len = s1.Read(buf, 0, buf.Length);
}
}
}
$Finally Achieved it :-) $
private void Form1_Load(object sender, EventArgs e)
{
RoutingClient=new TcpClient("127.0.0.1",5765);
ServerClient = new TcpClient("127.0.0.1", 5766);
rcStream = RoutingClient.GetStream();
ScStream = ServerClient.GetStream();
//start 2 threads
Thread t1 = new Thread(()=>ExchangePackets(rcStream,ScStream));
t1.Start();
Thread t2 = new Thread(() => ExchangePackets(ScStream, rcStream));
t2.Start();
}
private static void ExchangePackets(NetworkStream FirstStream, NetworkStream SecondStream)
{
try
{
while (true)
{
if (FirstStream.CanRead)
{
byte[] myReadBuffer = new byte[1024];
StringBuilder myCompleteMessage = new StringBuilder();
MemoryStream ms = new MemoryStream();
int numberOfBytesRead = 0;
int TotalBytesRead = 0;
// Incoming message may be larger than the buffer size.
do
{
numberOfBytesRead = FirstStream.Read(myReadBuffer, 0, myReadBuffer.Length);
ms.Write(myReadBuffer, TotalBytesRead, numberOfBytesRead);
myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
TotalBytesRead = TotalBytesRead + numberOfBytesRead;
}
while (FirstStream.DataAvailable);
MessageBox.Show("You received the following message : " +
myCompleteMessage);
if (SecondStream.CanWrite)
{
byte[] myWriteBuffer = ms.ToArray();
SecondStream.Write(myWriteBuffer, 0, myWriteBuffer.Length);
}
else
{
MessageBox.Show("Sorry. You cannot write to this NetworkStream.");
}
}
else
{
MessageBox.Show("Sorry. You cannot read from this NetworkStream.");
}
}
}
catch (Exception ex)
{
MessageBox.Show("Routing to Server:" + ex.Message);
}
}
EDIT: On closer examination, I don't think my answer is suitable for your situation. Your question describes a number of fixed constraints that might prevent you implementing it this way. I will leave my answer here for other people though, as I do think it is generally the right approach.
Is there any better way of exchanging packets between 2 Listening
ports by establishing connection to both ports?
You don't need to reinvent the wheel :)
You can use WCF to create a full-duplex service with TCP transport?
I just noticed that my socket client wasn't receiving the same data the server was sending back to it. The text gets cut off after 8192 characters.
Is there some limit I am not aware of? How do I get past this?
The client uses this code:
//Send and Receive
public string sendAndReceiveMSG(string msg)
{
try
{
NetworkStream serverStream = clientSocket.GetStream();
string sendresponse = sendMSG(msg, serverStream);
if (sendresponse == "ConnectionCrash")
{
return sendresponse;
}
else if (sendresponse == "OK")
{
string receiveresponse = receiveMSG(serverStream);
return receiveresponse;
}
return "UnknownErrorInternal";
}
catch (Exception ex)
{
return "UnknownErrorInternal";
}
}
//Send msg
private string sendMSG(string msg, NetworkStream serverStream)
{
try
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(msg);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
return "OK";
}
catch (Exception ex)
{
endSock();
return "ConnectionCrash";
}
}
//Receive msg
private string receiveMSG(NetworkStream serverStream)
{
try
{
byte[] inStream = new byte[10025];
int buffSize = clientSocket.ReceiveBufferSize;
dynamic bytesRead = serverStream.Read(inStream, 0, buffSize);
string returndata = System.Text.Encoding.ASCII.GetString(inStream, 0, bytesRead);
return returndata;
}
catch (Exception ex)
{
endSock();
return "ConnectionCrash";
}
}
The client then gets a response from the server like so;
string recv = client.sendAndReceiveMSG("someRequest");
You have only processed one call to Read. This behaviour is entirely expected; you very rarely get all the data in a single packet (frankly I'm amazed you didn't notice it sooner).
You need to decide on a "framing" policy (i.e. how you distinguish each sub-message - maybe new lines if text based, or length-prefix for binary) - and obtain a frames worth of data before processing. This usually means calling Read in a loop, or (for text) using something like a StreamReader which handles that for you (i.e. calling ReadLine() in a loop).
If there is only one message on the socket, and the caller closes their connection, you can dispense with framing, and just read until Read returns something non-positive (i.e. EOF).
Recently I have tackled a strange behaviour of .Net synchronous receive method. I needed to write an application that has nodes which communicate with each other by sending/receiving data. Each server has a receipt loop which is synchronous, after receiving a serialized class it deserializes and processes it. After that it sends asynchronously this serialized class to some chosen nodes (using AsynchSendTo).
The MSDN clearly says that:
"If you are using a connection-oriented Socket, the Receive method
will read as much data as is available, up to the size of the buffer.
If the remote host shuts down the Socket connection with the Shutdown
method, and all available data has been received, the Receive method
will complete immediately and return zero bytes."
In my case it's not true. There are some random cases when the Receive doesn't block and returns 0 bytes (non-deterministic situtation) right away after establishing connection. I'm 100% sure that the sender was sending at lest 1000 bytes. One more funny fact: when putting Sleep(500) before receive everything works just fine. Hereunder is the receiving code:
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
_listener.Bind(_serverEndpoint);
_listener.Listen(Int32.MaxValue);
while (true)
{
Console.WriteLine("Waiting for connection...");
Socket handler = _listener.Accept();
int totalBytes = 0;
int bytesRec;
var bytes = new byte[DATAGRAM_BUFFER];
do
{
//Thread.Sleep(500);
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
totalBytes += bytesRec;
} while (bytesRec > 0);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (SocketException e)
{
Console.WriteLine(e);
}
Also the sending part:
public void AsynchSendTo(Datagram datagram, IPEndPoint recipient)
{
byte[] byteDatagram = SerializeDatagram(datagram);
try
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket));
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
public void ConnectCallback(IAsyncResult result)
{
try
{
var stateObject = (StateObject)result.AsyncState;
var socket = stateObject.Socket;
socket.EndConnect(result);
socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket);
}
catch (Exception ex)
{
Console.WriteLine("catched!" + ex.ToString());
}
}
public void SendCallback(IAsyncResult result)
{
try
{
var client = (Socket)result.AsyncState;
client.EndSend(result);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
class StateObject
{
public Byte[] Data { get; set; }
public int Size;
public Socket Socket;
}
My question: am I using the synchronous receive in a wrong way? Why it doesn't block event though there is data to receive?
You're shooting yourself in the foot.
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
At the very beginning of the connection, Available will be 0, forcing it to return immediately with 0. Instead, you should specify the number of bytes which are free in your buffer (e.g. bytes.Length-totalBytes), then it will also block.
You may have a concurrency problem here. After you accept a connection, you jump straight into receive. The sender process may not have enough time to reach the call to send and so your handler.Available is 0 and the receive returns.
This is also why the "bug" does not occur when you add the sleep of 500 ms.