I have an ObservableCollection<MyClass> and I serialize its contents and send it using socket. Follow the code:
private const int Port = 3762;
private static SocketPermission permission = new SocketPermission(NetworkAccess.Accept, TransportType.Tcp, "", Port);
private static IPHostEntry ipEntry = Dns.GetHostEntry(string.Empty);
private static IPAddress ipAddress = ipEntry.AddressList[0];
private static IPEndPoint ipPoint = new IPEndPoint(ipAddress, Port);
Socket sTransmissao = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
using (var stream = new MemoryStream())
{
var binary = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binary.Serialize(stream, TransmissaoPendencias);
byte[] bArray = new byte[stream.Length];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(bArray, 0, (int)stream.Length);
sTransmissao.Connect(ipAddress, Port);
sTransmissao.Send(bArray);
}
But the byte length will change with the amount of items in my collection.
What is a viable solution to retrieving this information on the client side?
Thanks in advance.
You need to transmit the size before sending the array so that the other end knows how much to read.
Related
I have been struggling to fix my mistake. My client/server seems to work fine when on the same machine. When the code is executed on a different PC, for some reason only part of the bytes are reaching the server. I cannot seem to get the bytes to go through to matter how much I try. It seems the cutoff point is 367 bytes and it does not want to transfer anymore. If anyone knows what I am doing wrong, a solution would be much appreciated.
Thanks in advance!
Server:
using System;
using System.Data.SQLite;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
namespace DMAssist
{
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
// Current URL string
}
public class asyncserver
{
public asyncserver()
{
}
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public static string GetLocalIPAddress()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
throw new Exception("Local IP Address Not Found!");
}
public void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 25599);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public byte[] ObjectToByteArray(object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
private Object ByteArrayToObject(byte[] arrBytes)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object)binForm.Deserialize(memStream);
return obj;
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
String connectedAddress = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
IPEndPoint remoteIpEndPoint = handler.RemoteEndPoint as IPEndPoint;
connectedAddress = remoteIpEndPoint.Address.ToString();
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
Console.WriteLine("Bytes read: " + bytesRead);
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
object rawbytes = ByteArrayToObject(state.buffer);
netObject recvobject = (netObject)rawbytes;
Send(handler, (object)recvobject);
}
}
private void Send(Socket handler, object data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = ObjectToByteArray(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
Client:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Collections;
namespace DMAssist
{
public class asyncsclient {
public asyncsclient()
{
}
public byte[] ObjectToByteArray(object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
private Object ByteArrayToObject(byte[] arrBytes)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object)binForm.Deserialize(memStream);
return obj;
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
static string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
public object sendObject(object outgoingObject, bool expectRecieve)
{
try
{
Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("x.x.x.x");
IPEndPoint remoteEP = new IPEndPoint(ip, 25599);
soc.Connect(remoteEP);
byte[] byData = ObjectToByteArray(outgoingObject);
//Console.WriteLine("Array length:" + byData.Length);
soc.Send(byData);
if (expectRecieve)
{
byte[] buffer = new byte[1024];
int iRx = soc.Receive(buffer);
object rawbytes = ByteArrayToObject(buffer);
netObject recvobject = (netObject)rawbytes;
Console.WriteLine("Writing stopped");
soc.Close();
soc.Dispose();
return recvobject;
}
else
{
soc.Close();
soc.Dispose();
return "";
}
}
catch (Exception)
{
MessageBox.Show("Server unreachable. Make sure server is broadcasting on port 25599 successfully.", "DMAssist Error 0xC1");
}
return null;
}
}
}
There is a big difference between UDP sockets and TCP sockets.
What you are trying would work better with UDP because this protocol is more packet oriented. This means that if a server sends a certain number of bytes, the client 'might' receive the same certain number of bytes or receive nothing at all.
For TCP it is different because it is a streaming protocol which means bytes are just sent sequentially anyway the server sees fit. Usually it will try to fill up to the mtu and when you receive you will very likely receive the data in multiple chunks that you have to append yourself. TCP is a also connection oriented and reliable. Bytes are acked from the client to the server and vice versa, and retransmitted if an ack is not received in due time. This means even that packets can at the TCP level be received out of order. TCP will fit them together. You at the application level will receive everything in order.
The advice you got so far is correct, you have to keep calling receive. And this until there is nothing to receive anymore. And how do you know that there is nothing to receive anymore ? Usually that is detected by receiving a TCP message in receive with 0 length. This means that the peer has closed its end of the socket and will not send anymore. This in turn means that you can close your end of the socket.
This is by design. And it's a very common mistake developers make with regards to sockets.
To receive data correctly, you need to keep receiving data in a loop until you receive the number of bytes you need. Keep appending to your receive buffer until you get the number of bytes you need.
Some socket implementations have a the concept of a "wait for all" flag (e.g. MSG_WAITALL), but even that will return partial data if the remote closed the connection after sending.
Code defensively. Code as if the sender is only going to send 1 byte at a time. You'll be in good shape.
As you mentioned in your code, There might be more data, so you store the data received so far. But you don't have the code get the rest of the data.
MSDN has an example on how to do this correctly:
https://msdn.microsoft.com/en-us/library/bew39x2a.aspx?f=255&MSPPError=-2147217396
From winsock2.h:
#define MSG_WAITALL 0x8 /* do not complete until packet is completely filled */
You can add this option to your .net stream socket receive like this:
socket.Receive(buffer, (SocketFlags)0x8)
This should preserve message boundaries much like you're accustomed with dgram sockets.
I am trying to iterate each byte received over UDP and append that byte to a string (sbCardNo). The problem is the iteration for each byte is in the while loop, meaning a infinate loop (if I understand this correctly). How can I adapt the below code to add each byte to a string?
private void DoWork()
{
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 8888);
UdpClient newsock = new UdpClient(ipep);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
StringBuilder sbCardNo = new StringBuilder();
while (true)
{
data = newsock.Receive(ref sender);
sbCardNo.Append(data.GetValue(0));
FileStream fs = new FileStream(folderPath + "\\AuthService.txt",
FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter m_streamwriter = new StreamWriter(fs);
m_streamwriter.BaseStream.Seek(0, SeekOrigin.End);
m_streamwriter.WriteLine(sbCardNo);
m_streamwriter.Flush();
m_streamwriter.Close();
}
}
The above code gives me the following -
2
252
25267
2526748
252674848
25267484870
2526748487069
25267484870693
I just need the last line - 25267484870693
Thanks
Create the file at the end of the while and write all the contents of the StringBuilder at once, and handle logic for possible excpetions
In this example its reading until the byte 'Z' is received, but is much better if the other side of this comunication sends a single String or that the first 2 bytes is the length of the bytes that will be sent
private void DoWork()
{
byte ch ;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 8888);
UdpClient newsock = new UdpClient(ipep);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
StringBuilder sbCardNo = new StringBuilder();
while (true)
{
do
{
data = newsock.Receive(ref sender);
ch = data.GetValue(0)
sbCardNo.Append(ch);
} while (ch != 'Z') ;
using (StreamWriter m_streamwriter = new StreamWriter( folderPath + "\\AuthService.txt"))
{
m_streamwriter.WriteLine(sbCardNo.toString());
}
}
}
Using socket I can do so to get the bytes
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] buffer = new byte[1000000];
s.Receive(buffer, buffer.Length, SocketFlags.None);
//
FileStream fs = File.Create("1.jpg");
fs.Write(buffer, 0, buffer.Length);
fs.Close();
I use this code to receive a byte [] of an image that I'm sending.
I need to convert this code to use TcpClient / NetworkStream to receive the byte [] sent
enter code here
This Code should be equivalent to yours:
var buffer = new byte[100000];
using (TcpClient tcp = new TcpClient(AddressFamily.InterNetwork)
{
Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
})
{
await tcp.ConnectAsync("host", 12345);
if (tcp.Connected)
{
using (var stream = tcp.GetStream())
{
await stream.ReadAsync(buffer, 0, buffer.Length);
}
}
}
using (var fs = File.Create("1.jpg"))
{
await fs.WriteAsync(buffer, 0, buffer.Length);
}
I am trying to retrieve the byte that transferred by the server that has been programmed in c# as follow:
static void Main(String[] args){
Socket sListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress IP = IPAddress.Parse("10.0.0.92");
IPEndPoint IPE = new IPEndPoint(IP, 4321);
sListen.Bind(IPE);
Console.WriteLine("Service is listening ...");
sListen.Listen(2);
while (true){
Socket clientSocket;
try{
clientSocket = sListen.Accept();
}
catch{
throw;
}
byte[] buffer = ReadImageFile("path to image");
clientSocket.Send(buffer, buffer.Length, SocketFlags.None);
Console.WriteLine("Send success!");
}
}
private static byte[] ReadImageFile(String img){
FileInfo fileinfo = new FileInfo(img);
byte[] buf = new byte[fileinfo.Length];
FileStream fs = new FileStream(img, FileMode.Open, FileAccess.Read);
fs.Read(buf, 0, buf.Length);
fs.Close();
//fileInfo.Delete ();
GC.ReRegisterForFinalize(fileinfo);
GC.ReRegisterForFinalize(fs);
return buf;
}
Above codes works fine when I write a client in the c# and run it in the pc. However I want to retrieve the bytes transferred by the server in the android device.
The android connected to the server successfully but it will not finish its job, basically it will not pass the ‘while loop in the bellow code’. I think there is something wrong with the byte length because it’s never get to ‘-1’.
Android java code (Client):
Socket socket = new Socket("ip", 4321);
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024];
int read = is.read(buffer);
while(read != -1){
read = is.read(buffer);
}
is.close();
socket.close();
I do appreciate any help in advance,
Thanks,
The client read() method will never return -1 until the server closes the connection. You're not doing that so it never happens.
I don't get the point of your Java code. The read(byte[]) method you are using writes 1024 bytes (or less) in the buffer again and again. You are overwriting your previous buffer content. You probably would like to write the downloaded data to somewhere, like an OutputStream. Example:
Socket socket = new Socket("ip", 4321);
InputStream is = socket.getInputStream();
OutputStream os = ...; // Where to save data, for example, new ByteArrayOutputStream();
copyStreams(is, os);
is.close();
socket.close();
public static void copyStreams(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1024];
int numBytesRead;
for (;;) {
bytesRead = is.read(buffer);
if (bytesRead <= 0)
break;
os.write(buffer, 0, bytesRead);
}
}
byte[] bFileName = new byte[512];
r2Socket.Receive(bFileName);
String FileName = Encoding.UTF8.GetString(bFileName);
System.Windows.Forms.MessageBox.Show(FileName); // It's Ok. Show FileName = "text.jpg"
FileStream = new FileStream("D:\\" + FileName, FileMode.Create, FileAccess.Write);
FileStream ArgumentException
path is an empty string (""), contains only white space, or contains one or more invalid characters.
-or-
path refers to a non-file device, such as "con:", "com1:", "lpt1:", etc. in an NTFS environment.
Why it happens? thx.
==
//CLIENT
byte[] bFileName = new byte[512];
Socket Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket.Connect(textBoxIP.Text, int.Parse(textBoxPORT.Text));
FileInfo sFileInfo = new FileInfo(textBoxFILE.Text);
string FileName = sFileInfo.Name;
bFileName = Encoding.UTF8.GetBytes(FileName);
Socket.Send(bFileName);
//SERVER
Socket rSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress rIPAddress = Dns.GetHostEntry("localhost").AddressList[0];
IPEndPoint rIPEndPoint = new IPEndPoint(IPAddress.Any, int.Parse(textBoxPORT2.Text));
rSocket.Bind(rIPEndPoint);
rSocket.Listen(1);
byte[] bFileName = new byte[512];
r2Socket.Receive(bFileName);
String FileName = Encoding.UTF8.GetString(bFileName);
I'm going to guess it's because you are using UTF-8, and NTFS uses something else, thus the invalid characters error. I would try using another encoding.
Check out this SO post: What encoding are filenames in NTFS stored as?