I'm having a problem with the TCP client that I am working on. For some reason, the client seems to be connecting, but it's not reading anything to the output box. Here is the code:
private void button1_Click(object sender, EventArgs e)
{
string host = textBox1.Text;
int port;
port = Convert.ToInt32(textBox2.Text);
port = int.Parse(textBox2.Text);
string sendText = textBox3.Text;
Socket connectSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
connectSocket.Connect(host, port);
System.IO.StreamReader connectionRead
= new System.IO.StreamReader(new NetworkStream(connectSocket));
connectSocket.Send(System.Text.Encoding.UTF8.GetBytes(sendText));
while (connectionRead.Peek() > 0)
{
this.textBox4.AppendText(connectionRead.ReadLine() + "\r\n");
}
connectSocket.Close();
}
I'm sorry about the object names, I did this in a bit of a rush. It shouldn't be too hard to understand though. I'm taking user input from textBox(s) and putting it into variables.
I seem to be getting stuck at:
while (connectionRead.Peek() > 0)
{
this.textBox4.AppendText(connectionRead.ReadLine() + "\r\n");
}
Here, the program freezes for about 20 seconds, then unlocks with no output (the program does not crash).
Any help is appreciated greatly!
I think most of the problem lies in your assumption that if there is a character available in the stream (which you check with StreamReader.Peek()) then you currently have a full line of content available as well. There's no guarantee of this (you may have only received "Hello wo" of the data "Hello world\n"), so a call to ReadLine() would block until a '\n' is received.
However, I'm not sure why it's waiting 20 seconds each time before returning. The default ReadTimeout for NetworkStream is Timeout.Infinite. Are you sure the connection is not being terminated by the server? It may be configured to wait for around 20 seconds of "silence" before closing the connection (fairly common).
As an aside, you also may want to change your condition to while (connectionRead.Peek() > -1). Peek() returns a character integer, and 0 is a valid value ('\0').
Related
I implemented a little TCP connection to a program of mine, used for communication between a WPF application and a hosted Unity3D application.
I ran into a problem though when trying to re-open the window, the Unity3D application is hosted in.
public void SocketServer()
{
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
// use local m/c IP address, and
// use the same in the client
/* Initializes the Listener */
myList = new TcpListener(ipAd, 8002);
/* Start Listeneting at the specified port */
myList.Start();
MsgHandler placeHolderClass = new MsgHandler();
Debug.WriteLine("The server is running at port 8001...");
Console.WriteLine("The local End point is :" + myList.LocalEndpoint);
Console.WriteLine("Waiting for a connection.....");
s = myList.AcceptSocket();
while (true)
{
byte[] b = new byte[100];
int k = s.Receive(b);
Console.WriteLine("Recieved...");
string recived = "";
for (int i = 0; i < k; i++)
{
recived += Convert.ToChar(b[i]);
}
Console.Write(recived);
//ASCIIEncoding asen = new ASCIIEncoding();
//s.Send(asen.GetBytes("Hey I Got This Msg" + recived));
MsgUpdate = recived;
placeHolderClass.GetInfosFromDB(recived);
}
// Console.WriteLine("\nSent Acknowledgement");
/* clean up */
}
Is just something I found online. If I keep it this way and re-open the window, it throws an exception that the port is already in use. Fair enough, I never closed the connection. I get that. Then I went ahead and added
void PageUnloaded(object sender, RoutedEventArgs e) {
if(s != null) {
s.Shutdown(SocketShutdown.Both);
s.Close();
}
myList.Stop();
}
But this doesn't work. If I do it without the if-check, it tells me that s is null, which doesn't make sense, because if I check if it is null it still throws me an exception,
A blocking operation was interrupted by a call to WSACancelBlockingCall.
A quick search leads me to believe, that the thread containing my socket is actually closed before I even call my PageUnloaded function.
But how do I fix this? Is this even a good approach? I read online that this implementation is very bad - but then five searches later this seems to be the best approach possible for my needs. I'm at a loss here, can anyone point me in the right direction? Thanks! :)
I have a static method
public class TelnetClient
{
public static string SendAndReceiveData2(string data, string HostIPAddress, int Port)
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Connect(HostIPAddress, Port);
byte[] bytesToSend = Encoding.ASCII.GetBytes(data);
socket.ReceiveTimeout = 3000;
socket.SendTimeout = 3000;
int bytesSent = socket.Send(bytesToSend);
if (bytesSent != bytesToSend.Length)
{
throw new Exception("Invalid send byte number");
}
byte[] bytesReceiveBuffer = new byte[1024];
int bytesRec = socket.Receive(bytesReceiveBuffer); //No need to loop for testing
string returnedData = Encoding.ASCII.GetString(bytesReceiveBuffer, 0, bytesRec);
socket.Close(); // Just out of desperation
socket.Dispose();
return returnedData;
}
}
}
and this is how I am calling it:
for (int i = 0; i < 10; i++)
{
TelnetClient.SendAndReceiveData2("some data different each time", "127.0.0.1", 1234);
}
I am calling this method in a loop. This methods sends some commands to a third party application which returns a response immediately. The issue is that this code works for the first iteration but on the second iteration, it fails at socket.Receive with error:
A connection attempt failed because the connected party did not
properly respond after a period of time, or the established connection
failed because the connected host has failed to respond.
Here is the tricky part, If instead of looping multiple times, I close the exe and start again through command prompt, I don't get the error and also the third party app receives multiple requests as well.
This led me to believe that somehow the socket is not getting disposed properly in the loop. But if I close the process and start again, it has no problem.
I have checked that the socket.LocalEndPoint points to different port each time. Also socket.Available is set to 0 on second iteration.
I am not really sure what is going on, and would appreciate any help.
I notice that you are doing a Socket.Connect, but never doing a Socket.Disconnect.
From the MSDN website Socket.Disconnect will allow reuse of the socket and close the connection.
There is nothing wrong with the Socket and Socket disposal. The error message was bit misleading. The issue was at the server end.
More details....
Invalid data was being sent on the second iteration, when I tried sending exactly same data as the first iteration, it failed as well, because for each requests the server required a unique Guid id. That Guid was being generated outside the loop and hence it was used for all the items in the iteration. Restarting the process was working, because then I would get a new Guid for the first iteration.
I had never used UDP before, so I gave it a go. To see what would happen, I had the 'server' send data every half a second, and the client receive data every 3 seconds. So even though the server is sending data much faster than the client can receive, the client still receives it all neatly one by one.
Can anyone explain why/how this happens? Where is the data buffered exactly?
Send
class CSimpleSend
{
CSomeObjServer obj = new CSomeObjServer();
public CSimpleSend()
{
obj.changedVar = varUpdated;
obj.threadedChangeSomeVar();
}
private void varUpdated(int var)
{
string send = var.ToString();
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(send);
string ip = "127.0.0.1";
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
Console.WriteLine("Sent Message: " + send);
Thread.Sleep(100);
}
}
All CSomeObjServer does is increment an integer by one every half second
Receive
class CSimpleReceive
{
CSomeObjClient obj = new CSomeObjClient();
public Action<string> showMessage;
Int32 port = 11000;
UdpClient udpClient;
public CSimpleReceive()
{
udpClient = new UdpClient(port);
showMessage = Console.WriteLine;
Thread t = new Thread(() => ReceiveMessage());
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//Thread.Sleep(1000);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
if (showMessage != null)
showMessage("Recv:" + message);
int var_out = -1;
bool succ = Int32.TryParse(message, out var_out);
if (succ)
{
obj.alterSomeVar(var_out);
Console.WriteLine("Altered var to :" + var_out);
}
}
Thread.Sleep(3000);
}
}
}
CSomeObjClient stores the variable and has one function (alterSomeVar) to update it
Ouput:
Sent Message: 1
Recv:1
Altered var to :1
Sent Message: 2
Sent Message: 3
Sent Message: 4
Sent Message: 5
Recv:2
Altered var to :2
Sent Message: 6
Sent Message: 7
Sent Message: 8
Sent Message: 9
Sent Message: 10
Recv:3
Altered var to :3
The operating system kernel maintains separate send and receive buffers for each UDP and TCP socket. If you google SO_SNDBUF and SO_RCVBUF you'll find lots of information about them.
When you send data, it is copied from your application space into the send buffer. From there it is copied to the network interface card, and then onto the wire. The receive side is the reverse: NIC to receive buffer, where it waits until you read it. Additionally copies and buffering can also occur, depending on the OS.
It is critical to note that the sizes of these buffers can vary radically. Some systems might default to as little as 4 kilobytes, while others give you 2 megabytes. You can find the current size using getsockopt() with SO_SNDBUF or SO_RCVBUF and likewise set it using setsockopt(). But many systems limit the size of the buffer, sometimes to arbitrarily small amounts. This is typically a kernel value like net.core.wmem_max or net.core.rmem_max, but the exact reference will vary by system.
Also note that setsockopt() can fail even if you request an amount less than the supposed limit. So to actually get a desired size, you need to repeatedly call setsockopt() using decreasing amounts until it finally succeeds.
The following page is a Tech Note from my company which touches on this topic a little bit and provides references for some common systems: http://www.dataexpedition.com/support/notes/tn0024.html
It looks to me like the UdpClient-Class provides a buffer for received data. Try using a socket directly. You might also want to set that sockets ReceiveBufferSize to zero, even though I believe it is only used for TCP connections.
I've been having some trouble lately while trying to learn how to do an asynchronous receive using visual C#. I have a console based server program that receives data from a client and then sends it back. My problem is on the client side. It has to send data to the server every 100 or so milliseconds and then receive it back.
The problem is getting it back because I can't have the program stop and wait for data. Here's what it looks like so far...
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 16487);
TcpClient client = new TcpClient();
bool blnOnOFF;
private void SendServerData()
{
string strData = "TEST DATA";
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(strData);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
// Ticks Every 100ms
private void tmrDataTransfer_Tick(object sender, EventArgs e)
{
SendServerData();
}
private void btnStart(object sender, EventArgs e)
{
if (blnOnOFF == false)
{
tmrDataTransfer.Start();
blnOnOFF = true;
}
else
{
tmrDataTransfer.Stop();
blnOnOFF = false;
}
}
As you can see, all it does right now is send "TEST DATA". If there is another way to receive the data that is simpler than asynchronous please let me know, also i would like to learn how to do this for future projects.
thanks in advanced.
EDIT: added client sorry i forgot about it
Ok, so, what you need to do is when your app is waiting for incoming data, you need to employ the TcpListener class.
Try this SO answer
The TcpListener class listens for incoming connections, and when it finds one, it creates a TcpClient which does its thing. Meanwhile, the listener has already gone back to looking for new connections. It's pretty much only ever doing just that, and moving the work off to other places.
I think (70% sure) that the TcpClient it creates for a new connection will be operating on a different port than the one your listener is using. You're thus always listening on the same port, while your processing is done on other threads on other ports.
Make sense? I can elaborate more if desired.
I'm developing an application that is running a lot of TcpListener tasks
using c# with .net 3.5 on windows server 2008
the TcpListener task is:
listening
to get an xml message
read an ID
from it
send a command to a
specific camera based on the ID to
take a snapshot and store it in a
folder
This is meant to execute within 1 second so I can take a snapshot with the camera. I've got a delay in executing this task, using the following code:
private Thread listen_thread;
public void start_listen()
{
this.listen_thread = new Thread(new ThreadStart(save_data));
this.listen_thread.Priority = ThreadPriority.Normal;
this.listen_thread.Start();
}
private void save_data()
{
//work to be done
}
Is this the best multi-threading technique to use? This application is running on a on dell poweredge 2900
with 2 quad core prosessor, and I think it could go faster. How might I be able to improve the latency of this code?
thats the code for the tcplistener
Int32 port = controller_port;
try
{
//this server ip
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
Console.Write("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
string add_data = "";
Console.Write("Waiting...!");
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
try
{
string full_row = "";
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.Write("Received from controller: " + data);
add_data += data;
}
catch{}
}
}
}
then i divide it to get the ID .
It's not clear at all
how you receive requests
upon what you parallelize the application
It seems that you listen on different sockets and assign a thread on each of them.
I think this is a poor choice, because you can't control the parallelism degree.
You could instead have just one thread that nondeterministically listens on all sockets and assigns the connection to a thread pool, configured to simultaneously run at most n threads, where n is the parallelism degree of your machine (if you have a dual quadcore, n is equal to 8).
These methods have strikingly wrong names. start_listen() doesn't start listening. save_data() cannot possibly save any data until at least a connection is established. Which requires the client code to start up first and make the connection. Sure, one second is quickly gone with that. Starting a thread doesn't take more than a fraction of a millisecond when there's a core available.
Focus on the code that's missing in your snippet.