how to handle received TCP packets in socket programming C# - c#

I have a txt file that is 150kb. and i want to send it via socket programming and in a custom way:
I want to send first 136160 bytes through port x and 13840 bytes through another port (port y).
At the destination it also receives the first 136160 bytes but drops the next 13840 bytes.
In fact, I want this packet dropping to be dynamic so for each file we can individually specify how many bytes should be dropped.
I have the sender part of code and really in need of the codes in receiver part.
Thanks in advance for your answers and assistance
here is the normal codes of receiver which i use:
public void Listen(){
Socket SoListen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint IPE = new IPEndPoint(IPAddress.Any, int.Parse(txtPort.Text));
SoListen.Bind(IPE);
SoListen.Listen(2);
Socket CGetFile = SoListen.Accept();
byte[] bfile = new byte[1024 * 1000000];
while (true)
{
int r = CGetFile.Receive(bfile);
if (r > 0)
{
this.Invoke(new Action(() =>
{
lblStatus.Text = "recieving";
SaveFileDialog SD = new SaveFileDialog();
if (SD.ShowDialog() == DialogResult.OK)
{
FileStream fs = new FileStream(SD.FileName, FileMode.Create);
fs.Write(bfile, 0, r);
fs.Flush();
lblStatus.Text = "recieved";
}
}));
Thread.CurrentThread.Abort();
}
}
}

Related

Bad audio while sending through TCP/IP connection

I'm making an application that sends audio through TCP/IP connection using NAudio.
This is my server code:
// Get server port.
var iServerPort = GetServerPort();
// Initialize memory stream.
_bytes = new List<byte>();
// Initialize tcp listener.
var tcpListener = new TcpListener(IPAddress.Any, iServerPort);
tcpListener.Start();
// Accept a tcp client.
Console.WriteLine("Waiting for incoming connection");
_tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("Client found !");
// Buffered wave provider.
_bufferedWaveProvider = new BufferedWaveProvider(new WaveFormat());
_bufferedWaveProvider.DiscardOnBufferOverflow = true;
_bufferedWaveProvider.BufferLength = iBufferBytes;
_waveOut = new WaveOut();
_waveOut.Init(_bufferedWaveProvider);
_waveOut.Play();
// Initialize a thread to listen to incoming data from another source.
_tcpConnectionListeningThread = new Thread(() =>
{
// Get data stream of tcp connection.
var networkStream = _tcpClient.GetStream();
// Initalize buffer.
var buffer = new byte[iBufferBytes];
// Number of bytes which have been read.
while (true)
{
try
{
int iReadBytes;
while ((iReadBytes = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
//var memoryStream = new MemoryStream();
//memoryStream.Write(buffer, 0, iReadBytes);
//_memoryStreams.Enqueue(memoryStream);
//_memoryStream.CopyTo();
//_memoryStream.Write(buffer, 0, iReadBytes);
var realBytes = buffer.Take(iReadBytes).ToList();
_bytes.AddRange(realBytes);
Console.WriteLine($"Read: {iReadBytes} bytes. Enqueue a stream. Count: {realBytes.Count}");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
break;
}
}
});
// Initialize a thread to check audio buffer. Reload as audio stream consumes whole data.
_waveBufferCheckThread = new Thread(() =>
{
while (true)
{
// Get remaining bytes in buffer.
var iRemainingBytes = _bufferedWaveProvider.BufferedBytes;
// No byte is available in buffer.
// Check memory stream to find available bytes array. If nothing found, terminate this thread.
if (iRemainingBytes >= iBufferBytes)
continue;
// No byte available.
if (_bytes.Count < 1)
{
//Console.WriteLine("No data in memory stream");
continue;
}
// Get bytes array from memory stream.
var iDifferent = iBufferBytes - iRemainingBytes;
if (iDifferent > _bytes.Count)
iDifferent = _bytes.Count;
var bytes = _bytes.GetRange(0, iDifferent).ToArray();
_bytes.RemoveRange(0, iDifferent);
//var bytes = new byte[iBufferBytes];
_bufferedWaveProvider.AddSamples(bytes, 0, bytes.Length);
//Console.WriteLine($"Wrote {iReadBytes} to buffer. Count: {_memoryStream.Length}");
//Thread.Sleep(TimeSpan.FromSeconds(1));
//_waveOut.Play();
}
});
_tcpConnectionListeningThread.IsBackground = true;
_waveBufferCheckThread.IsBackground = true;
_tcpConnectionListeningThread.Start();
_waveBufferCheckThread.Start();
Console.ReadLine();
_tcpConnectionListeningThread.Abort();
_waveBufferCheckThread.Abort();
_bufferedWaveProvider.ClearBuffer();
_waveOut.Stop();
tcpListener.Stop();
This is my client code:
public Main()
{
InitializeComponent();
// Initialize tcp client.
_tcpClient = new TcpClient();
_recordingStream = new MemoryStream();
_soundRecorder = new WaveIn();
_waveOut = new WaveOut();
_playbackBufferedWaveProvider = new BufferedWaveProvider(_soundRecorder.WaveFormat);
_waveOut.Init(_playbackBufferedWaveProvider);
_soundRecorder.DataAvailable += SoundRecorderOnDataAvailable;
btnRecord.Enabled = true;
}
private void SoundRecorderOnDataAvailable(object sender, WaveInEventArgs waveInEventArgs)
{
if (_networkStream != null)
{
_networkStream.Write(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
_networkStream.Flush();
}
}
My application works fine. But there is one problem I'm facing with :
- The recorded voice cannot be heard while sending to server end-point. If I save it to memory stream and play it back, the quality is ok.
Should I compress my recorded voice before sending to server ? Are there any ways to solve this issue ?
Thank you,
Your _tcpConnectionListeningThread should be writing directly into the BufferedWaveProvider, not going through an intermediate step of copying into an non-thread safe list. _waveBufferCheckThread is completely unnecessary. Update the listening thread to do something like:
while ((iReadBytes = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
_bufferedWaveProvider.AddSamples(buffer, 0, iReadBytes);
}
Also you must ensure the WaveFormat on the server side is exactly the same as used on the client side.

C# - Sockets not receiving all bytes

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.

How to make sure that stream is read completely?

I am using Network Stream, TcpListener and Sockets.
I want to make sure that all the data from sender is received by receiver.
I have below code for receiver
private void StartReciever()
{
util.LoadSettings();
string tcpIpAddress = util.svrSettings["IpAddress"];
string port = util.svrSettings["Port"];
string outDir = util.svrSettings["isOutput"];
new Thread(
() =>
{
if (!File.Exists(util.settingFile))
Logger("Please setup the services first.");
else
{
try
{
IPAddress ipAddress = IPAddress.Parse(tcpIpAddress);
TcpListener tcpListener = new TcpListener(ipAddress, Convert.ToInt32(port));
tcpListener.Start();
Logger("\nWaiting for a client to connect...");
//blocks until a client connects
Socket socketForClient = tcpListener.AcceptSocket();
Logger("\nClient connected");
//Read data sent from client
NetworkStream networkStream = new NetworkStream(socketForClient);
int bytesReceived, totalReceived = 0;
string fileName = "testing.txt";
byte[] receivedData = new byte[10000];
do
{
bytesReceived = networkStream.Read
(receivedData, 0, receivedData.Length);
totalReceived += bytesReceived;
Logger("Progress of bytes recieved: " + totalReceived.ToString());
if (!File.Exists(fileName))
{
using (File.Create(fileName)) { };
}
using (var stream = new FileStream(fileName, FileMode.Append))
{
stream.Write(receivedData, 0, bytesReceived);
}
}
while (bytesReceived != 0);
Logger("Total bytes read: " + totalReceived.ToString());
socketForClient.Close();
Logger("Client disconnected...");
tcpListener.Stop();
}
catch (Exception ex)
{
// Error : "Only one usage of each socket address (protocol/network address/port) is normally permitted"
Logger("There is some error: " + ex.Message);
}
}
}).Start();
}
How can I make sure that my code after do-while loop executes ?
Sender Code:
private static void SendData(string tcpIpAddress, string port, string filename)
{
new Thread(
() =>
{
TcpClient tcpClient = new TcpClient(tcpIpAddress, Convert.ToInt32(port));
//const int bufsize = 8192;
const int bufsize = 10000;
var buffer = new byte[bufsize];
NetworkStream networkStream = tcpClient.GetStream();
using (var readFile = File.OpenRead(filename))
{
int actuallyRead;
while ((actuallyRead = readFile.Read(buffer, 0, bufsize)) > 0)
{
networkStream.Write(buffer, 0, actuallyRead);
}
}
}).Start();
}
How can I make sure that my code after do-while loop executes?
Here, it's easy because you can close the connection on the sender which will cause the receiver to read zero bytes and terminate the loop.
In fact you forgot to clean up the sender. Dispose of all resources. This fixes the problem.
Your code would benefit from the Code Review SE. I see about a dozen issues immaterial to this question. Would be a great way for you to improve yourself.
For example you can replace the copy loops with Stream.Copy.
The usual way I've seen this done to prepend the data being sent with the number of bytes about to be sent. That way the receiver knows that the packet has been read. Even if the network gets interrupted or the sender sends something else without a break.
Note that doing this you can also read the first 8 bytes (or 4 if an Int32 will do the job) before allocating the read buffer which can help optimise the buffer size
Another common way of doing it is with a specific terminator, but then you have to guarantee that whatever you're sending cannot contain that terminator

Append to a string in an infinite iteration inside a windows service

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());
}
}
}

Android retrieve bytes from inputstream

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);
}
}

Categories