I have this method which i use to send a Transfer object
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 7777);
Socket sockListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
sockListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sockListener.Bind(ipEnd);
sockListener.Listen(100);
s = sockListener.Accept();
private void sendToClient(Transfer.Transfer tt)
{
byte[] buffer = new byte[15000];
IFormatter f = new BinaryFormatter();
Stream stream = new MemoryStream(buffer);
f.Serialize(stream, tt);
Console.WriteLine("1/3 serialized");
stream.Flush();
Console.WriteLine("2/3 flushed stream");
s.Send(buffer, buffer.Length, 0);
Console.WriteLine("3/3 send to client");
}
The strange thing is it work the first 2 times i call it, then on the 3rd call it hangs on s.send().
Its the same if i want to send String instead of Transfer.
The comment by #nos is probably correct, the TCP Send buffer is probably filling up and the 3rd call to s.send() is blocking until the data is sent over the network. You can set the used buffer sizes like this:
Socket s = sockListener.Accept();
s.ReceiveBufferSize = 1024 * 64;
s.SendBufferSize = 1024 * 64;
You should be able to confirm your problem by setting your buffer sizes to a larger multiple of the size of data you're sending.
Also, as suggested, you should check the client to make sure its reading the data properly.
Related
I am trying to send a stream through UDP socket. The "SendTo" takes byte[] buffer argument. Not sure how to do this if I have a stream object (buffer). Please help! Thanks. The ByteBufferOutputStream does not seem to have a funciton to convert the stream to bytes.
ByteBufferOutputStream buffer = new ByteBufferOutputStream();
Avro.IO.Encoder ej = new BinaryEncoder(buffer);
ej.WriteInt(Convert.ToInt32(testEvent["schemaId"]));
var dwrd = new DefaultWriter(schema);
dwrd.Write<GenericRecord>(testEvent, ej);
buffer.Flush();
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Udp);
IPAddress serverAddr = IPAddress.Parse("192.168.1.1");
IPEndPoint endPoint = new IPEndPoint(serverAddr, 2190);
clientSocket.SendTo(buffer, endPoint);
Actually it does. ByteBufferOutputStream has a method named GetBufferList, which returns an
IEnumerable of System.IO.MemoryStream. You can take these MemoryStreams, and concatenate them to a single buffer, with an integer header specifying how many streams are there (denoted by X), followed by X more integers specifying the length of the ordered streams, followed by the streams themselves.
You can send that entire buffer via UDP to your server, where it will reconstruct the streams, and
use ByteBufferInputStream (from Avro) which has a constructor that accepts them.
I am writing a C# client application which will connect to the server written in python. My question is about receiving data in loop. The application structure is all about client asks server -> server responds to client. Everything works fine when the message is lower that actual buffer size (set in server). For example: server side buffer: 1024, client buffer size: 256, data length < 1kb. I run my application with following code:
int datacounter = 0;
byte[] recived = new byte[256];
StringBuilder stb = new StringBuilder();
serverStream.ReadTimeout = 1500;
try
{
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
Console.WriteLine("RECIVED: " + datacounter.ToString());
stb.append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
}
}
catch { Console.WriteLine("Timeout!"); }
Then the application receives data in 4 loops (256 bytes each):
RECIVED: 256
RECIVED: 256
RECIVED: 256
RECIVED: 96
And then the timeout ticks, that ends the transmission and pass the complete data to later analysis (from stb object). I don't think using timeout is proper, but i don't know any other way to do this.
However, this way it works. Here we go with example, that does not:
server side buffer: 1024, client side buffer: 256, data length ~ 8kbytes (python side sends data in loop).
RECIVED: 256
RECIVED: 256
RECIVED: 256
RECIVED: 256
Then the timeout ticks (and obviosly the data is incomplete - got 1kb of 8kb). Sometimes the loop even ends after 1 run with 28 recived bytes and thats all before timeout. Python says that the data has been send properly. Here's the way i create the socket and serverStream object:
TcpClient clientSocket = new TcpClient();
clientSocket.Connect("x.y.z.x", 1234);
NetworkStream serverStream = clientSocket.GetStream();
Its not the TcpClient fault. Tried the same with clear sockets, created like:
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
However that works similar. Is there a way, to make my loop work without timeout, receiving all data? I would like to keep the socket synchronous if possible.
I don't think there's anything wrong with your receive code functionally. I put together a test, and the receiver gets as much as you can send it (eg. 8 MBs), as long as you keep sending without 1.5 seconds pause, before timing out.
So it looks like your server is simply not sending "fast" enough.
To answer your question, timing is not the typical way of knowing when you have received a full message. One common, simple way of determining when a full message is received is to prefix the length of the full message on the sending side (eg. 4-byte int). Then on the receive side, first read 4 bytes, decode to the length, and then read that many more bytes.
You could also consider appending a message termination string, such as Environment.NewLine, to the end of your message. This has the advantage that you could call StreamReader.ReadLine(), which will block until the full message is received. This only works if the termination can NOT be included in the message itself.
If you can't alter the server protocol, is there any other way of knowing you have received a full message? (eg. checking for a NewLine at the end of the message, an XML end tag, or some other pattern.) If not, perhaps you could wait for the server to disconnect, otherwise it looks like you would be forced to find the right timing balance.
I am including the test code below in case you want to play around with it.
Server/Sending Side:
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
TcpListener server = new TcpListener(localAddr, 13579);
server.Start();
TcpClient clientSocket = server.AcceptTcpClient();
NetworkStream stream = clientSocket.GetStream();
int bytesSent = 0;
int bytesToSend = 1 << 25;
int bufferSize = 1024;
string testMessage = new string('X', bufferSize);
byte[] buffer = UTF8Encoding.UTF8.GetBytes(testMessage);
while (bytesSent < bytesToSend)
{
int byteToSendThisRound = Math.Min(bufferSize, bytesToSend - bytesSent);
stream.Write(buffer, 0, byteToSendThisRound);
bytesSent += byteToSendThisRound;
}
Client/Receiving Side:
TcpClient client = new TcpClient("127.0.0.1", 13579);
NetworkStream serverStream = client.GetStream();
int totalBytesReceived = 0;
int datacounter = 0;
byte[] recived = new byte[256];
StringBuilder stb = new StringBuilder();
serverStream.ReadTimeout = 1500;
try
{
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
totalBytesReceived += 256;
Console.WriteLine("RECIVED: {0}, {1}", datacounter, totalBytesReceived);
stb.Append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
}
}
catch { Console.WriteLine("Timeout!"); }
Why don't you dump the exception that makes your code go into the catch branch and find out? :)
catch (Exception ex) { Console.WriteLine("Timeout because of... " + ex.Message); }
--EDIT
Sorry I didn't see the timout. The question you're asking is if there's a way to do it without timeout. Yes, don't set any timeout and check if received number of bytes is smaller than the buffer size.
That is:
while ((datacounter = serverStream.Read(recived, 0, 256)) > 0)
{
Console.WriteLine("RECIVED: " + datacounter.ToString());
stb.append(System.Text.Encoding.UTF8.GetString(recived, 0, datacounter));
if(datacounter < 256) //you're good to go
break;
}
For anyone else who needs help with this
Just to add to Chi_Town_Don's answer, make sure you use stb.ToString() outside of the loop. And I've found that nothing will print out unless the loop breaks out. To do that if(!serverStream.DataAvailable()){break;} works wonders. That way you don't need to pass in the packet size or some other convoluted condition.
I wrote c# client-server application, server is sending data using socket.send(byte[]) and receive using socket.receive(byte[]) now i want to send and receive from android and totally new to android.
i appreciate any kind of help.
//client side
Socket sendChannel=new Socket("localhost", 12345);
OutputStream writer=sendChannel.getOutputStream();
writer.write(new byte[]{1});
writer.flush();
InputStream reader=sendChannel.getInputStream();
byte array[]=new byte[1];
int i=reader.read(array);
//server side
ServerSocket s=new ServerSocket(12345);
Socket receiveChannel = s.accept();
OutputStream writerServer=receiveChannel.getOutputStream();
writer.write(new byte[]{1});
writer.flush();
InputStream readerServer=receiveChannel.getInputStream();
byte array2[]=new byte[1];
int i2=reader.read(array);
You can use a TCP socket and a input stream to read data in a separate thread from the main application thread in your android app like this:
// Start a thread
new Thread(new Runnable() {
#Override
public void run() {
// Open a socket to the server
Socket socket = new Socket("192.168.1.1", 80);
// Get the stream from which to read data from
// the server
InputStream is = socket.getInputStream();
// Buffer the input stream
BufferedInputStream bis = new BufferedInputStream(is);
// Create a buffer in which to store the data
byte[] buffer = new byte[1024];
// Read in 8 bytes into the first 8 bytes in buffer
int countBytesRead = bis.read(buffer, 0, 8);
// Do something with the data
// Get the output stream from the socket to write data back to the server
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
// Write the same 8 bytes at the beginning of the buffer back to the server
bos.write(buffer, 0, 8);
// Flush the data in the socket to the server
bos.flush();
// Close the socket
socket.close();
}
});
You can wrap the input stream in various other types of stream if you want to read in multibyte values such as shorts or ints (DataInputStream). These will take care of converting from network endianess to the native endianess of the client.
You can get an output stream from the socket to write data back to the server.
Hope this helps.
I have been struggling for a while now to send an image file over sockets. I believe I am very close, but I haven't gotten it yet. I am trying to send the image from the server to the client.
Here is my server code:
//Init listener
listener = new TcpListener(new IPEndPoint(IPAddress.Any, 550));
//Start listening for connections
listener.Start();
Console.WriteLine("Waiting for connection");
s = listener.AcceptSocket();
//If we reach here, we have a connection
Console.WriteLine("Connected");
//Get the screenshot and apply it to our memory stream
img = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
imgG = Graphics.FromImage(img);
imgG.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
ms = new MemoryStream();
img.Save(ms, ImageFormat.Jpeg);
img.Save("sc.jpg", ImageFormat.Jpeg);
//Convert image to byte array, and then send it
byte[] byteArray = ms.ToArray();
s.Send(byteArray);
s.Close();
Console.Read();
Here is my client code:
client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse(IPBox.Text), 550));
s = client.Client;
buffer = new byte[100000];
s.Receive(buffer);
ms.Read(buffer, 0, 100000);
img = (Bitmap)Image.FromStream(ms);
imgContainer.Image = (Image)img;
I think I am very close, but I might be far off. I am new to networking, and require help please. Thanks A lot.
The problem is that in your client, you are assuming that you received 100000 bytes from the server, and you're putting all 100000 bytes into the memory stream.
There is a great sample on the MSDN page for TcpClient which shows receiving from a TcpClient by using the underlying NetworkStream. Also, you will want to keep track of how many bytes you actually received (this is the return value from the NetworkStream.Read function). Finally, you'll want to keep reading until there is no more data to be read from the host. If your image is larger than your buffer, then you'll only have a partial image also. The sample on the linked page for NetworkStream.Read shows continually reading from the stream while there is data available.
When u know why the sent string "kamote" to server and the string received "kamote" from server are not the same..
CLIENT
tcpClient = new TcpClient();
tcpClient.Connect(ServerIP, Port);
connectionState = (HandShake("kamote", tcpClient)) ? "Connected to " + ServerIP.ToString() : "Host unreachable.";
private bool HandShake(String str, TcpClient tcpClient)
{
using (NetworkStream ns = tcpClient.GetStream())
{
byte[] toServer = Encoding.ASCII.GetBytes(str);
ns.Write(toServer,0,toServer.Length);
ns.Flush();
byte[] fromServer = new byte[10025];
ns.Read(fromServer, 0, (int)tcpClient.ReceiveBufferSize);
return Encoding.ASCII.GetString(fromServer).Equals(str);
}
}
SERVER
TcpClient tcpClient = new TcpClient();
tcpClient = tcpListener.AcceptTcpClient();
NetworkStream ns = tcpClient.GetStream();
byte[] fromClient = new byte[10025];
ns.Read(fromClient, 0, (int)tcpClient.ReceiveBufferSize);
byte[] toClient = fromClient;
ns.Write(toClient, 0, toClient.Length);
ns.Flush();
Client sent "kamote"
Server received "kamote"
Server sent "kamote"
Client received "kamote"
HandShake() always returns false. How can I fix this?
As in the previous question you asked, you're not keeping track of the number of bytes you received. So what's happening is this:
On the client, you send the string "kamote".
On the server, it receives that string into a buffer that's 10025 bytes long.
The server then sends the entire buffer back to the client -- all 10025 bytes
The client receives all or part of those 10025 bytes and converts them to a string.
The string that gets converted is really "kamote" with a bunch of 0's after it.
You must use the return value from Read to know how many bytes you received.
Did you try limiting the string length to the actual read bytes like this:
noOfBytes = ns.Read(bytes, 0, ...);
Encoding.ASCII.GetString(bytes, 0, noOfBytes);
You are including a lot of 0 characters, since you are including the entire fromServer in getstring. 0s don't print, but they are there. You must tell it the correct number of bytes to decode.