TCPClient Error: "System.InvalidOperationExceptio" - c#

I've been creating a TCPClient which is suppose to connect to a server but am getting this error:
System.InvalidOperationException: 'The operation is not allowed on
non-connected sockets.'
Here's my Code:
Public String IPAddress = "192.168.100.xxx"
Public Int32 Port = 23;
public TcpClient client = new TcpClient();
public void Connect() {
client.Connect(IPAddress, Port);
// send first message request to server
Byte[] msg_data = System.Text.Encoding.ASCII.GetBytes("Hello Server);
// uses the GetStream public method to return the NetworkStream
NetworkStream netStream = _client.GetStream();
// write message to the network
netStream.Write(msg_data, 0, msg_data.Length);
// buffer to store the response bytes
msg_data = new Byte[256];
// read the first batch of response byte from arduino server
Int32 bytes = netStream.Read(msg_data, 0, msg_data.Length);
received_msg = System.Text.Encoding.ASCII.GetString(msg_data, 0, bytes);
netStream.Close();
}
public void Send() {
// message data byes to be sent to server
Byte[] msg_data = System.Text.Encoding.ASCII.GetBytes(_sendMessage);
// uses the GetStream public method to return the NetworkStream
// ** Error Here: System.InvalidOperationException: 'The operation is not allowed on non-connected sockets.'
NetworkStream netStream = client.GetStream();
// write message to the network
netStream.Write(msg_data, 0, msg_data.Length);
// buffer to store the response bytes
msg_data = new Byte[256];
// read the first batch of response byte from arduino server
Int32 bytes = netStream.Read(msg_data, 0, msg_data.Length);
received_msg = System.Text.Encoding.ASCII.GetString(msg_data, 0, bytes);
netStream.Close(); // close Stream
}
I am getting and error when creating a new instance of NetworkStream netStream = client.GetStream();. Been struggling to find whats causing the error, I think it's somehow closing the connection above.
Everything is in a class and must be called at anyplace in the software.

client.GetStream() is implemented like:
return new NetworkStream(this.Client, true);
whereas the true means if the stream is disposed/closed it also closes/disconnects the socket/client. You should be able to avoid this by directly calling
var netStream = new NetworkStream(client.Client, false);
And even better would be instead of:
NetworkStream netStream = client.GetStream();
…
netSteam.Dlose();
to ensure that the stream is always closed even if an errors by writing:
using (var netStream = new NetworkStream(client.Client, false))
{
…
}

Related

I have multiple TcpClient connections, how do I select a specific one?

I have a TCP Client
Log.Warn("Trying to connect to " + IP);
TcpClient client = new TcpClient(IP, Port);
string command = "";
while (!command.Contains("quit"))
{
Log.WriteSingle("localhost#", ConsoleColor.DarkYellow);
Log.WriteSingle(IP + ":", ConsoleColor.Yellow);
command = Console.ReadLine();
byte[] data = Encoding.ASCII.GetBytes(command);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Log.Success("Sent command to network.");
// Buffer to store the response bytes.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Log.Write("Server Says: " + responseData, ConsoleColor.DarkYellow);
}
and a TCP Server
while(true)
{
Log.Write("Waiting for connection...");
TcpClient client = server.AcceptTcpClient();
Log.Success("Connected! ");
//Update list (Currently useless)
clientList.Add(client);
Thread t = new Thread(new ThreadStart(()=>ConnectClient(client,bytes,data)));
t.Start();
}
public static void ConnectClient(TcpClient _client, byte[] _bytes, string _data)
{
_data = null;
NetworkStream stream = _client.GetStream();
int i;
while((i = stream.Read(_bytes,0,_bytes.Length))!=0)
{
_data = System.Text.Encoding.ASCII.GetString(_bytes,0,i);
Log.Write("Recieved: "+_data, ConsoleColor.Cyan);
//Send back to client
_data = _data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(_data);
stream.Write(msg,0,msg.Length);
Log.Write("Sent: "+_data);
}
_client.Close();
}
I have it setup so the server listens to client connections and pop them off in a new thread once they connect. The client can send the server a string, and the server reflects it back.
I assume I can use a dictionary to assign an ID and store the client, or even just a simple List.
How would I structure it so I can add them to a List or a Dictionary and still be able to connect multiple clients?
Thanks
Put your accept() loop in a thread of its own. It can add to the list each time a new client connects.
Leave your main thread to manage all the client threads, including the accept() thread.

TcpClient does not flush writes

I have this code to send String messages to a server. These messages are supposed to be sent separately, but the Stream of the TcpClient is sending the messages in one bug chunk after the Stream is closed.
What can I do to send separated messages with this code:
public void sendData()
{
const int PORT_NO = 12900;
const string SERVER_IP = "127.0.0.1";
TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
try
{
client.NoDelay = true;
NetworkStream nwStream = client.GetStream();
sendText(nwStream, "Text-1"); // Here is it supposed to send "Text-1"
sendText(nwStream, "Text-2");
sendText(nwStream, "Text-3");
}
finally
{
client.Close(); // But, all messages are sent here!
}
}
private void sendText(NetworkStream nwStream, String text)
{
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(text);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
nwStream.Flush();
}
With this code the Server ends up receiveing: Text-1Text-2Text-3 in one message and it is supposed to receive 3 different messages. What is wrong here?

Receive full data

I wrote a small program that receives a huge string over TCP.
I am able to read from the network stream only one time and then the program crashes. How can I fix this problem or can you suggest me a better way to send big string over TCP. The client's buffer size is 202601176 (The string bytes length).
This is my code:
namespace File_Transfer_Server
{
class Program
{
static void Main(string[] args)
{
TcpListener serverListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 6666);
serverListener.Start();
TcpClient tcpClient = serverListener.AcceptTcpClient();
Console.WriteLine(">>> Receiving");
byte[] clientBuffer = new byte[1024];
Console.WriteLine(clientBuffer.Length);
using (NetworkStream clientNStream = tcpClient.GetStream())
{
int i;
string received = "";
while ((i = clientNStream.Read(clientBuffer, 0, clientBuffer.Length)) > 0) //exception
{
string data = Encoding.ASCII.GetString(clientBuffer, 0, i);
received += data;
Console.WriteLine(data);
}
File.WriteAllText(#"E:\receivedData.txt", received);
Console.WriteLine(">>>Done");
}
}
}
}
This is the exception:
Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at File_Transfer_Server.Program.Main(String[] args) in D:\Files from PC\Visual Basic Projects - =&+Ivan+&=\Tesseract\Temp\File Transfer\File_Transfer_Server\Program.cs:line 29
EDIT:
Client code:
namespace File_Transfer_Client
{
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 6666);
NetworkStream clientNetworkStream = client.GetStream();
string fileContent = FileBase64Encoding(#"D:\Download\AtomSetup-x64.exe");
byte[] fileBytes = Encoding.ASCII.GetBytes(fileContent);
// byte[] fileLength = Encoding.ASCII.GetBytes(fileBytes.Length.ToString());
Console.WriteLine(fileBytes.Length);
clientNetworkStream.Write(fileBytes, 0, fileBytes.Length);
Console.WriteLine("Send");
}
static string FileBase64Encoding(string path)
{
byte[] fileBytes = File.ReadAllBytes(path);
string fileBase64String = Convert.ToBase64String(fileBytes);
return fileBase64String;
}
}
}
The issue with your code is the client closes connection before the server manages to receive all the data. You have to tell the server about the length of your message. This is called "Message Framing".
Solution
Write the length of the message before it's content and read it at the server end.
Allocate the buffer at the server with the size of message length.
Read message contents.
Optional step: To make sure we won't have any Socket exceptions Make the client wait for the server until it receives all the data. Server closes the connection.
Client code:
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 6666);
NetworkStream clientNetworkStream = client.GetStream();
string fileContent = FileBase64Encoding(#"D:\Download\AtomSetup-x64.exe");
byte[] fileBytes = Encoding.ASCII.GetBytes(fileContent);
// byte[] fileLength = Encoding.ASCII.GetBytes(fileBytes.Length.ToString());
Console.WriteLine(fileBytes.Length);
// Write the length of a message
var integerBytes = BitConverter.GetBytes(fileBytes.Length); // integer has 4 bytes
clientNetworkStream.Write(integerBytes, 0, integerBytes.Length);
// Write the contents
clientNetworkStream.Write(fileBytes, 0, fileBytes.Length);
Console.WriteLine("Send");
// Wait for server to finish receiving
clientNetworkStream.ReadByte();
Console.WriteLine("Connection closed");
}
static string FileBase64Encoding(string path)
{
byte[] fileBytes = File.ReadAllBytes(path);
string fileBase64String = Convert.ToBase64String(fileBytes);
return fileBase64String;
}
Server code:
class Program
{
static void Main(string[] args)
{
TcpListener serverListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 6666);
serverListener.Start();
TcpClient tcpClient = serverListener.AcceptTcpClient();
Console.WriteLine(">>> Receiving");
byte[] clientBuffer;
using (NetworkStream clientNStream = tcpClient.GetStream())
{
int i;
string received = "";
byte[] integerBytes = new byte[sizeof(int)];
clientNStream.Read(integerBytes, 0, integerBytes.Length); // receive message length
int messageLength = BitConverter.ToInt32(integerBytes, 0);
Console.WriteLine("Received message length: {0}", messageLength);
clientBuffer = new byte[messageLength]; // allocate buffer
clientNStream.Read(clientBuffer, 0, clientBuffer.Length); // read string contents
Console.WriteLine("Received all the data");
// we're done
Console.WriteLine("Closing connection");
tcpClient.Close();
received = Encoding.ASCII.GetString(clientBuffer, 0, clientBuffer.Length);
File.WriteAllText(#"E:\receivedData.txt", received);
Console.WriteLine(">>>Done");
}
}
}
As you can see the code for the server now is simpler.
Ideally you would want some more advanced message framing mechanism that can split your message into much smaller chunks and write directly to a file, because you will run out of memory for really big files and is always good idea to split big messages into smaller chunks.

Netty server and C# Socket Client. Receive on client doesn't work

I want to receive message on C# client from Netty server. I use sync C# socket and protobuf.
I send message to server and it's ok. But I can't receive response.
Netty server uses ProtobufDecoder. Server ChannelInboundHandler has this part of code:
public void channelRead0(final ChannelHandlerContext ctx, Object msg) {
...
Set<String> keys = jedis.keys("tanks*");
String allKeys = "";
for(String key: keys){
allKeys+=key+";";
}
ctx.write(allKeys);
ctx.flush();
}
C# client code is:
const string server = "localhost";
const int port = 8080;
var tcpClient = new TcpClient(server, port);
_networkStream = tcpClient.GetStream();
var stream = new MemoryStream();
Serializer.Serialize(stream, tankDataObject);
var data = stream.ToArray();
_networkStream.Write(data, 0, data.Length);
data = new Byte[10000];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = _networkStream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
// Close everything.
_networkStream.Close();
tcpClient.Close();
Client doesn't receive any bytes or receive empty array if I call ctx.close() on server. Any help will be appreciated. Thank you.

TcpClient connection receive and sent timeout

I am using TcpClient to connect to a socket, below is the sample code, which I connect to the socket once to retain conenction session id, then I keep on transmitting and receiving message from the socket, until I found a valid message, then I stop:
// client is a global object to retain connection session id
TcpClient client = new TcpClient("127.0.0.1", 1800);
public void Connect()
{
message = "First message"; // first message
do
{
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new Byte[256];
String responseData = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
} while (message = "valid") // loop untill message is valid
stream.Close();
client.Close();
}
My question is how can I use the TcpClient.ReceiveTimeout and TcpClient.SentTimeout 20 seconds effectively in my code?
Am I doing the right thing with the TcpClient connection to retain the connection session id?
Thank you.

Categories

Resources