I am trying to implement a tcp client listening function. This means that after connection established with server, this tcp client just sit there and waiting for new data to arrive.
Here is my code but when it runs, it complain about not been able to read anything from the
network stream. But the server hasn't started sending data yet. I guess the complains is because
of the timeout in tcp client.
Is this the right way to do it?
public void listen(dataHandler processDataFuc)
{
NetworkStream stream;
Byte[] data_buffer = new Byte[MAX_PACKET_SIZE];
if(!this.Connected)
{
this.Connect();
}
while (!this.terminate_listening)
{
stream = main_client.GetStream();
while (stream.Read(data_buffer, 0, data_buffer.Length) > 0)
{
processDataFuc(data_buffer);
}
}
}
Thanks
The short answer is yes, it'll do what you want, but it's not ideal. I'd first suggest moving stream = main_client.GetStream(); out of the while loop, as you're just getting the same stream over and over. Also, using NetworkStream.Read isn't the best way to perform a continuous read if you're expecting intermittent data over a long period of time, as it's holding up a thread just for that one task; better to use BeginRead and pass in a callback, which will return immediately but later alert you when data is available (via the callback).
Checkout the methods EstablishConnection() and IncomingDataSyncWorker() (synchronous) or IncomingPacketHandler() (asynchronous) for examples of what you want to do. All these methods are part of networkComms.net an opensource network communication library.
What version of .Net are you using?
If you are using .Net 4.0 or 4.5, then you can use ReadAsync() instead of Read().
Consider this:
public async void listen(dataHandler processDataFuc)
{
NetworkStream stream;
Byte[] data_buffer = new Byte[MAX_PACKET_SIZE];
if(!this.Connected)
this.Connect();
stream = main_client.GetStream();
while (!this.terminate_listening)
{
await stream.ReadAsync(data_buffer, 0, data_buffer.Length)
processDataFuc(data_buffer);
}
}
In such way, ReadAsync() will waits in a separate Thread until server sends some Data. Then the rest of your code will execute.
Related
I have client-server application in C#.Net and for that I am using Tcp Socket. I have used following function to aggressive close of socket object.
void CloseSocket(Socket socket)
{
if(socket != null)
{
socket.ShutDown(ocketShutdown.Both);
socket.Close();
}
}
In Normal Condition this function works perfectly and my method returns with 0 bytes returned from Read function.
But whenever client process terminated by taskmanager server program blocks into read function of network stream.
How can I workaround this read blocking function ? I don't want to use AsyncRead function because whole project uses blocking strategy so write now I can't change it to Async pattern.
Thanks, in advance.
I'm assuming that what you are saying is that when the connection isn't closed cleanly by the client, the server can end up blocking at Read indefinitely, even if the client has actually terminated abruptly. If so: yes, that happens. So if you want to use the synchronous read methods, you should use timeouts, in particular ReceiveTimeout. If you have a multi-message protocol, it may be worthwhile adding some kind of heartbeat message periodically, to allow you to correctly identify true zombies from idle connections (for example: if you are sending a heartbeat every minute, and you haven't seen any activity on a connection for 3 minutes, hit it with a shovel).
**you can try this may help you**
public void close()
{
if(clientSocket != null )
{
sendCommand("QUIT");
}
cleanup();
}
private void cleanup()
{
if(clientSocket!=null)
{
clientSocket.Close();
clientSocket = null;
}
logined = false;
}
Basically, I've written a windows phone 7 client, which is supposed to receive a very long string from the server. However, there seem to be some limitations on the phone networking code, and am having trouble figuring out how to do this. The following is the code I am using:
public string Receive()
{
string response = "Operation Timeout";
StringBuilder content = new StringBuilder();
// We are receiving over an established socket connection
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
_socket.ReceiveAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
As it stands, this will only accept the first N bytes of the message and return that... any help on how to do this would be greatly appreciated! Thanks!
Firstly, I would try to redesign your code to be appropriately async - working round the fact that WP7 doesn't offer synchronous IO by building your own isn't nearly as clean as embracing the asynchrony.
Secondly, you're assuming that you only need a single ReceiveAsync call to get the whole data. Assuming your using TCP, that's a stream-based protocol. You'll need to either add some sort of delimiter or length prefix, or keep reading until the other side closes the connection if that's the way your protocol works.
(Any reason you're not doing this with HTTP and WebClient or WebRequest, by the way?)
Firstly, I would try to redesign your code to be appropriately async - working round the fact that WP7 doesn't offer synchronous IO by building your own isn't nearly as clean as embracing the asynchrony.
Secondly, you're assuming that you only need a single ReceiveAsync call to get the whole data. Assuming your using TCP, that's a stream-based protocol. You'll need to either add some sort of delimiter or length prefix, or keep reading until the other side closes the connection if that's the way your protocol works.
(Any reason you're not doing this with HTTP and WebClient or WebRequest, by the way?)
I'm trying to create a chat with file transfer application using TCPSocket and here is my code..
SENDER:
public void sendData(string message)
{
StreamWriter streamWriter = new StreamWriter(netStream); // netStream is
// connected
streamWriter.WriteLine(message);
streamWriter.WriteLine(message);
logs.Add(string.Format("Message Sent! :{0}", message));
//netStream.Flush();
streamWriter.Flush();
}
RECEIVER:
private void ReceiveData()
{
StreamReader streamReader = new StreamReader(ChatNetStream);
StringBuilder dataAppends = new StringBuilder();
bool doneTransfer = false;
string data;
while (!doneTransfer)
{
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
doneTransfer = true;
//ChatNetStream.Close();
//streamReader
}
//do whatever i want with dataAppends.ToString() here..
ReceiveData()
}
the problem is i always turn into infinite loop inside this statement
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
even if i put streamWriter.Flush() on my sender..
do i need to close/dispose the netStream/NetworkStream?
anyway, can i use only 1 socket or connection to send a File and send a chat at the same time..? or do i need to use a new socket connection everytime i send a file..
You get an infinite loop because StreamReader.ReadLine will only return null when the end of the stream is reached. For a network stream, "end of stream" means "the other side has closed its half of the connection". Since the other side is your client, and it keeps the connection open while waiting for the user to type in more data, you will end up with an infinite loop.
What you want to do instead is fire off an operation that only completes if there is more data to read. There are two ways to go about this: either use a blocking read operation (on a dedicated thread, so that you don't block your application's other processing while waiting for messages), or use an async (event- or callback-based) approach.
For the synchronous (blocking) approach, see the documentation on NetworkStream.Read which includes example code that shows how to check if there is incoming data and how you can read it. The one point you absolutely need to know here is that when Read returns zero, it means that all data has been read and the connection has been closed from the other side (so you should close your end as well and not loop; the client has disconnected).
For low-level async network reads, the relevant operation is NetworkStream.BeginRead, which comes with its own example.
Both approaches are lower-level than what you currently have and will require you to manually assemble data inside a buffer and decide when "enough data" (i.e. a full line) has accumulated for you to process. You will then have to carefully pull that data out of the buffer and continue.
For a higher-level approach that still allows you some degree of orchestrating things, look into using client sockets (and in particular the two sync and async options there). This functionality is introduced by the TcpClient (and server-side the corresponding TcpListener) classes.
Finally, as jValdron's comment says, you will either need a separate connection for transferring file data or engineer some custom protocol that allows you to interleave multiple kinds of data over the same network stream. The second solution is has generally more technical merit, but it will also be harder for you to implement correctly.
Checkout the BasicSend example in networkComms.net which demonstrates a simple chat application using an open source library.
I am using the following code (built from answers to my previous questions on SO):
public void Start()
{
listener = new TcpListener(IPAddress.Any, 9030);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept();
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
int readCount;
while ((readCount = ns.Read(data, 0, client.ReceiveBufferSize)) != 0)
{
sb.Append(Encoding.UTF8.GetString(data, 0, readCount));
}
// Do work
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
The line "Do work" represents where I will do the required processing for my client.
However I can't see how to use this code to read the client's data and then reply to it. When using this code I can read perfectly what is sent by my client, however once that occurs the client locks up and eventually complains that the connection was terminated. It does not receive my reply.
Any ideas on how to fix this?
Okay, first of all, you are mixing asynchronous calls (BeginAcceptTcpClient) and synchronous (Read and Write) calls. That completely kills the purpose of asynchronous code. Second, maybe this is why your socket gets closed ? Performing a sync op on an async socket. I'm not sure, but without the client code it's impossible to tell.
Anyway, this is NOT how you build an asynchronous, multi-client server.
Here is a fully asynchronous server implementation : http://msdn.microsoft.com/en-us/library/fx6588te.aspx
i think you should use a length byte to alloc your buffer. ReceiveBufferSize could be called multiple times, i think there is no gurantee you receive everything in one block.
You have misunderstood how Read works. It blocks until something is received from the other end point. The only time it returns 0 is when the other side have disconnected, hence you will continue reading until the other side disconnects.
When using TCP you need to know when a message ends. You can do that either by sending the message length first as a header or by using a suffix (as a line feed) after each message. Then you should keep reading until the complete message has arrived.
i am trying to disconnect a client from a server but the server still sees it as being connected. I cant find a solution to this and Shutdown, Disconnect and Close all dont work.
Some code for my disconnect from the client and checking on the server:
Client:
private void btnDisconnect_Click(object sender, EventArgs e)
{
connTemp.Client.Shutdown(SocketShutdown.Both);
connTemp.Client.Disconnect(false);
connTemp.GetStream().Close();
connTemp.Close();
}
Server:
while (client != null && client.Connected)
{
NetworkStream stream = client.GetStream();
data = null;
try
{
if (stream.DataAvailable)
{
data = ReadStringFromClient(client, stream);
WriteToConsole("Received Command: " + data);
}
} // So on and so on...
There are more writes and reads further down in the code.
Hope you all can help.
UPDATE: I even tried passing the TCP client by ref, assuming there was a scope issue and client.Connected remains true even after a read. What is going wrong?
Second Update!!:
Here is the solution. Do a peek and based on that, determine if you are connected or not.
if (client.Client.Poll(0, SelectMode.SelectRead))
{
byte[] checkConn = new byte[1];
if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
{
throw new IOException();
}
}
Here is the solution!!
if (client.Client.Poll(0, SelectMode.SelectRead))
{
byte[] checkConn = new byte[1];
if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
{
throw new IOException();
}
}
From the MSDN Documentation:
The Connected property gets the
connection state of the Client socket
as of the last I/O operation.
When it
returns false, the Client socket was
either never connected, or is no
longer connected. Because the
Connected property only reflects the
state of the connection as of the most
recent operation, you should attempt
to send or receive a message to
determine the current state. After the
message send fails, this property no
longer returns true. Note that this
behavior is by design. You cannot
reliably test the state of the
connection because, in the time
between the test and a send/receive,
the connection could have been lost.
Your code should assume the socket is
connected, and gracefully handle
failed transmissions.
I am not sure about the NetworkStream class but I would think that it would behave similar to the Socket class as it is primarily a wrapper class. In general the server would be unaware that the client disconnected from the socket unless it performs an I/O operation on the socket (a read or a write). However, when you call BeginRead on the socket the callback is not called until there is data to be read from the socket, so calling EndRead and getting a bytes read return result of 0 (zero) means the socket was disconnected. If you use Read and get a zero bytes read result I suspect that you can check the Connected property on the underlying Socket class and it will be false if the client disconnected since an I/O operation was performed on the socket.
It's a general TCP problem, see:
How do I check if a SSLSocket connection is sane on Java?
Java socket not throwing exceptions on a dead socket?
The workaround for this tend to rely on sending the amount of data to expect as part of the protocol. That's what HTTP 1.1 does using the Content-Length header (for a entire entity) or with chunked transfer encoding (with various chunk sizes).
Another way is to send "NOOP" or similar commands (essentially messages that do nothing but make sure the communication is still open) as part of your protocol regularly.
(You can also add to your protocol a command that the client can send to the server to close the connection cleanly, but not getting it won't mean the client hasn't disconnected.)