C# Socket Send and Receive on Same Machine - c#

I am in the process of making a C# socket library that can be accessed in Visual FoxPro. Ideally, the library will contain two functions: ReceiveMessage and SendMessage. On each call, the function is supposed to {open connection -> read/write -> close connection}. I found most of what I am looking for at http://www.csharp-examples.net/socket-send-receive/; however, now I have to test (on the same machine) the modified code before compiling the dll.
I keep getting a "connection actively refused" error. While I have included all of the code below so you can see what it is doing, the issue is almost certainly in the main() at the bottom. It is my limited understanding that I cannot have two connections to the same port, but I am at a loss on how to fix it. Does anybody know sockets who can give me some direction on how to test these functions (I am new to sockets)?
namespace Sockets
{
class Sockets
{
private static void Receive(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
int startTickCount = Environment.TickCount;
int received = 0; // how many bytes is already received
do
{
if (Environment.TickCount > startTickCount + timeout)
throw new Exception("Timeout.");
try
{
received += socket.Receive(buffer, offset + received, size - received, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably empty, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (received < size);
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
private static void Send(Socket socket, byte[] buffer, int offset, int size, int timeout)
{
int startTickCount = Environment.TickCount;
int sent = 0; // how many bytes is already sent
do
{
if (Environment.TickCount > startTickCount + timeout)
throw new Exception("Timeout.");
try
{
sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
throw ex; // any serious error occurr
}
} while (sent < size);
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
public static string SendMessage(string ipAddress, string port, string message)
{
Socket socket = new TcpClient().Client;
try
{
socket.Connect(ipAddress, Int32.Parse(port));
Send(socket, Encoding.UTF8.GetBytes(message), 0, message.Length, 10000);
socket.Close();
return "Success";
}
catch (Exception e)
{
socket.Close();
return e.Message;
}
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
public static string ReceiveMessage(string ipAddress, string port, int bufferSize = 1024)
{
Socket socket = new TcpClient().Client;
try
{
socket.Connect(ipAddress, Int32.Parse(port));
byte[] buffer = new byte[bufferSize];
Receive(socket, buffer, 0, buffer.Length, 10000);
socket.Close();
return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
}
catch (Exception e)
{
socket.Close();
return e.Message;
}
}
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
}
}
class Program
{
static void Main(string[] args)
{
new Thread(delegate() {var test = Sockets.Sockets.SendMessage("localhost", "60010", "abcdefg");}).Start();
new Thread(delegate() {Console.WriteLine(Sockets.Sockets.ReceiveMessage("localhost", "60010"));}).Start();
var waitForEnter = Console.ReadLine();
}
}

With a tilda (~) as the trailing character, here is the functional receive function (old code is commented):
public static string ReceiveMessage(string ipAddress, string port, int bufferSize = 1024)
{
try
{
TcpListener serverSocket = new TcpListener(new System.Net.IPAddress(IPAddress.Parse(ipAddress).GetAddressBytes()), Int32.Parse(port));
serverSocket.Start();
TcpClient clientSocket = serverSocket.AcceptTcpClient();
NetworkStream networkStream = clientSocket.GetStream();
int bytesRead;
string buffer = "";
byte[] bytesFrom = new byte[bufferSize];
while (true)
{
bytesRead = networkStream.Read(bytesFrom, 0, bytesFrom.Length);
string incoming = System.Text.Encoding.ASCII.GetString(bytesFrom, 0, bytesRead);
buffer = buffer + incoming;
while (buffer.Contains("~"))
{
string msg = buffer.Substring(0, buffer.IndexOf("~"));
// buffer = buffer.Remove(0, msg.Length + 3);
return msg;
}
}
//var socket = new TcpListener(new IPAddress(IPAddress.Parse(ipAddress).GetAddressBytes()), Int32.Parse(port));
//try
//{
//byte[] buffer = new byte[bufferSize];
// Receive(socket, buffer, 0, buffer.Length, 10000);
// socket.Close();
// return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
//}
//catch (Exception e)
//{
// socket.Close();
// return e.Message;
//}
}
catch (Exception e)
{
return e.Message;
}
}

Related

Async TCPClient missing replies from server

I'm trying to implement an async TCP client that sends messages from a queue and listens to the response.
some of the server replies are lost (for example send 7 messages and get only 4 replies) and I don't understand why.
This is not a server issue, since the synchronize version I tested works just fine.
ConcurrentQueue<byte[]> msgQueue = new ConcurrentQueue<byte[]>();
public void Connect()
{
try
{
tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
Task.Factory.StartNew(() =>
{
IAsyncResult res = tcpclnt.BeginConnect(_ip, _port, null, null);
if (!res.AsyncWaitHandle.WaitOne(CONNECTION_TIMEOUT_SEC * 1000))
{
tcpclnt.Close();
throw new ApplicationException("timed out trying to connect");
}
tcpclnt.EndConnect(res);
Receive();
byte[] message = null;
while (true)
{
message = null;
msgQueue.TryDequeue(out message);
if (message != null)
{
Stream stm = tcpclnt.GetStream();
Console.WriteLine("Transmitting..... " + Thread.CurrentThread.ManagedThreadId);//for debug
stm.Write(message.ToArray(), 0, message.ToArray().Length);
Receive();
}
}
});
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
//will be called from outside
public void SendMessage(byte[] msg)
{
Console.WriteLine("SendMessage..... " + Thread.CurrentThread.ManagedThreadId);//for debug
msgQueue.Enqueue(msg);
}
private void Receive()
{
SocketError error;
byte[] buffer = new byte[MAX_BUFFER_SIZE];
tcpclnt.Client.BeginReceive(buffer, 0, MAX_BUFFER_SIZE, SocketFlags.None, out error, new AsyncCallback(ReceiveHandler), buffer);
}
private void ReceiveHandler(IAsyncResult ar)
{
System.Console.WriteLine("ReceiveHandler " + Thread.CurrentThread.ManagedThreadId); //for debug
//End current async receive
int bytesRead = tcpclnt.Client.EndReceive(ar);
byte[] resultBuffer = (byte[]) ar.AsyncState;
// do a lot of things with resultBuffer
}

how to get connectionaborted immediately in Asynchronous Programming?

I was doing Asynchronous Programming in c# when I came across this question,when the network is aborted.
My program can get a exception of ConnectionAborted almost 15 seconds after I send a invaild message from client to server.
My question is if I want to get the exception immediately after the network doesn't work,what need I do.
namespace _10_TCP模块化编程
{
class ObjectState
{
public Socket client;
public MyTcp obj;
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
class MyTcp
{
public delegate void dReceiver(object sender, string b);
public event dReceiver receive;
public Socket WebHabor;
//private bool connected;
public MyTcp(IPEndPoint iep, dReceiver dEventCall)
{
//接收消息的委托;
receive += dEventCall;
//创建socket连接;
WebHabor = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ObjectState obs = new ObjectState();
obs.obj = this;
obs.client = WebHabor;
WebHabor.BeginConnect(iep, new AsyncCallback(ConnectCallback), obs);
//connected = WebHabor.Connected ? true : false;
Thread.Sleep(10);
if (WebHabor.Connected == true)
{
Receive();
}
else
{
Program.postLog("连接失败,请检查ip和port");
}
}
public static void ExceptionSolver(SocketException sep)
{
switch (sep.SocketErrorCode)
{
case SocketError.NotConnected:
//捕获ip地址输入错误的情况;
Program.postLog("不存在网络连接");
break;
case SocketError.ConnectionAborted:
//在这里处理频繁出现的错误,
//比如IP不对,网线没插
Program.postLog("连接中止");
break;
case SocketError.ConnectionRefused:
//远程主机正在主动拒绝连接;可能是连接的时候ip或port写错了;
Program.postLog("对方不接受连接,更可能是port的原因");
break;
case SocketError.HostUnreachable:
Program.postLog("连接目标不可达");
break;
case SocketError.TimedOut:
//尝试连接ip超时;
Program.postLog("尝试连接ip超时,更可能是ip的原因");
break;
default:
Program.postLog("捕获到" + sep.SocketErrorCode);
//这里直接报错,如果调试的时候出现这里的错误比较多,就移到上面解决,一般问题都是从来不出的
break;
}
}
public void Send(byte[] dataToSend,int byteCount)
{
try
{
WebHabor.BeginSend(dataToSend, 0, byteCount, 0, new AsyncCallback(SendCallback), WebHabor);
//System.Threading.Thread.Sleep(10);//为了让其它线程跑起来;
}
catch (SocketException sep)
{
Program.postLog("在Send这里");
ExceptionSolver(sep);
}
}
public void Receive()
{
byte[] buffer = new byte[256];
ObjectState obs = new ObjectState();
obs.obj = this;//这个传的是MyTcp;
obs.client = WebHabor;
try
{
WebHabor.BeginReceive(obs.buffer, 0, ObjectState.BufferSize, 0, new AsyncCallback(ReceiveCallback), obs);
}
catch (SocketException sep)
{
Program.postLog("在reveive这里");
ExceptionSolver(sep);
}
//receive.Invoke(this, buffer);
}
//beginConnect的回调函数;
private static void ConnectCallback(IAsyncResult ar)
{
ObjectState obs = (ObjectState)ar.AsyncState;
try
{
// Retrieve the socket from the state object.
Socket client = obs.client;
// Complete the connection.
client.EndConnect(ar);
//Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
//连上就连上吧就不发数据了
//MessageBox.Show("Socket connected to " + client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
//connectDone.Set();
}
catch (SocketException sep)
{
//Console.WriteLine(e.ToString());
//MessageBox.Show("connect回调函数出错了" + e.ToString());
/*********************************************************************
*
* 此处需要考察一下连接失败的异常情况。
*
*********************************************************************/
//obs.obj.connected = false;
Program.postLog("在ConnectCallback这里");
ExceptionSolver(sep);
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
//System.Threading.Thread.Sleep(10);//为了让其它线程跑起来;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Program.postLog("本次发送" + bytesSent + "个字节");
//Console.WriteLine("Sent {0} bytes to server.", bytesSent);
//MessageBox.Show("Sent " + bytesSent + " bytes to server.");
// Signal that all bytes have been sent.
//sendDone.Set();
}
catch (SocketException sep)
{
//MessageBox.Show("Send回调函数出错了" + e.ToString());
/*********************************************************************
*
* 此处需要考察一下发送失败的异常情况。
*
*********************************************************************/
Program.postLog("在SendCallback这里");
ExceptionSolver(sep);
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
//byte[] buffer = new byte[256];
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
//StateObject state = (StateObject)ar.AsyncState;
//Socket client = state.workSocket;
// Read data from the remote device.
ObjectState objs = (ObjectState)ar.AsyncState;
Socket client = objs.client;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
string getMsg = Encoding.ASCII.GetString(objs.buffer, 0, bytesRead);
//Console.WriteLine("新得到的数据是" + getMsg + "呵呵");
//MessageBox.Show("新得到的数据是" + getMsg);
string msg=Encoding.Default.GetString(objs.buffer, 0, bytesRead);
Program.postLog(msg);
//objs.obj.receive.Invoke(objs.obj, msg);//因为这是静态函数,这个objs.obj实际是MyTcp实例。
//MessageBox.Show(bytesRead.ToString() + "更新数据后:" + state.sb.ToString());
// Get the rest of the data.
client.BeginReceive(objs.buffer, 0, objs.buffer.Length, 0, new AsyncCallback(ReceiveCallback), objs);
}
else
{
//接到0字节说明对方主动断开了连接;
Program.postLog("对方主动断开连接");
}
}
catch (SocketException sep)
{
//MessageBox.Show("Receive回调函数出错了" + e.ToString());
/*********************************************************************
*
* 此处需要考察一下接收失败的异常情况。
*
*********************************************************************/
Program.postLog("在ReceiveCallback这里");
ExceptionSolver(sep);
}
}
}
}
I am not sure, but you can try using TcpClient.Client.Poll method as mentioned in one of the post.

Client-Server application do nothing when trying to get response from server C#/

I'm writing client-server application. Client sending command and server recieves it and do some manipulations. It works well. But when i'm trying to send response from server to client and recieve it on client side nothing happens. Even server do nothing. Program hangs and only Shift+F5 helps to finish it.
Server code:
class TNPClient
{
TNPBaseInterraction tnp_base;
private void SendError(TcpClient Client, int Code)
{
byte[] buf = Encoding.ASCII.GetBytes(Code.ToString());
Client.GetStream().Write(buf, 0, buf.Length);
Client.Close();
}
private void SendResponse(TcpClient Client, string response)
{
byte[] buf = Encoding.ASCII.GetBytes(response);
Client.GetStream().Write(buf, 0, buf.Length);
Client.Close();
}
void ParseMonitorRequest(TcpClient Client, string req)
{
MessageBox.Show("inside parser");
int term_id = Convert.ToInt32(req.Substring(2));
switch (req[1])
{
case '0':
List<MonitorStruct> monitors = tnp_base.GetMonitors(term_id);
foreach (MonitorStruct mon in monitors)
{
}
break;
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
MessageBox.Show("inside 4");
List<TerminalStruct> terminals = tnp_base.GetTerminals();
foreach (TerminalStruct term in terminals)
{
MessageBox.Show("sending response");
MessageBox.Show(string.Format("ID: {0} Address: {1} Comment: {2}", term.TerminalID, term.Address, term.Comment));
//SendResponse(Client, string.Format("ID: {0} Address: {1} Comment: {2}", term.TerminalID, term.Address, term.Comment));
}
break;
}
}
void ParseTerminalRequest(TcpClient Client, string req)
{
}
public TNPClient(TcpClient Client)
{
try
{
tnp_base = new TNPBaseInterraction("127.0.0.1", "tnp", "tnp_user", "tnp123", "3406");
string Request = "";
byte[] buf = new byte[1024];
int Count = 0;
while ((Count = Client.GetStream().Read(buf, 0, buf.Length)) > 0)
{
Request += Encoding.ASCII.GetString(buf, 0, Count);
}
if (Request[0].Equals('0'))
{
ParseMonitorRequest(Client, Request);
}
else
{
ParseTerminalRequest(Client, Request);
}
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
}
}
class TNPServer
{
TcpListener Listener;
int Port = 5252;
public TNPServer(int ServerPort)
{
int MaxThreadsCount = Environment.ProcessorCount * 4;
ThreadPool.SetMaxThreads(MaxThreadsCount, MaxThreadsCount);
ThreadPool.SetMinThreads(2, 2);
Port = ServerPort;
}
public void StartServer()
{
Listener = new TcpListener(IPAddress.Any, Port);
Listener.Start();
while (true)
{
ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(ClientThread), Listener.AcceptTcpClient());
}
}
static void ClientThread(Object StateInfo)
{
new TNPClient((TcpClient)StateInfo);
}
~TNPServer()
{
if (Listener != null)
{
Listener.Stop();
}
}
}
Client side code (this code gives problem):
try
{
TcpClient client = new TcpClient("127.0.0.1", 5365);
if (client.Connected) MessageBox.Show("Connected");
byte[] buf = Encoding.ASCII.GetBytes(tbSendText.Text);
NetworkStream stream = client.GetStream();
stream.Write(buf, 0, buf.Length);
// System.Threading.Thread.Sleep(5000);
//client.ReceiveTimeout = Convert.ToInt32(TimeSpan.FromSeconds(1).TotalMilliseconds);
byte[] buffer = new byte[256];
int Count = 0;
string response = string.Empty;
// while ((Count = client.GetStream().Read(buffer, 0, buffer.Length)) > 0)
//{
Count = stream.Read(buffer, 0, buffer.Length);
response = Encoding.ASCII.GetString(buffer, 0, Count);
//}
stream.Close();
client.Close();
MessageBox.Show(response);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
All messages on server side are shown then i'm not trying to get response on client side. When i'm trying to get response no messages are shown, but connection is established.
In server side, the read loop is blocked forever. You need to read only up to to the length of the text & then parse the request. You can write the length of the text from client side & then write the content.

Network stream is not reading the last 8192 bytes of data, tripping out of the while loop

I'm reading a huge byte of around 3824726 bytes. I've tried a lot of functions for reading the whole bytes. It is reading exactly 3816534 bytes and the while loop is going away some where. Remaining 8192 bytes are not being read and also there is no exception. It reads till exactly 3816534 and then when on while loop goes away somewhere. Please some one help and tell what may be the problem here. I have tried a lot but the same thing is happening in different functions.
public static void ReadFully(NetworkStream stream, int initialLength)
{
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[initialLength];
int chunk;
try
{
int read = -1;
int totread = 0;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
totread += read;
Console.WriteLine("Toatal Read" + totread);
string filePath = "C:\\Foo.txt";
StreamWriter objWriter;
using (objWriter = File.AppendText(filePath))
{
objWriter.WriteLine(totread);
objWriter.Flush();
objWriter.Close();
}
}
Console.WriteLine("Toatal Read" + totread);
}
catch (Exception ex)
{ throw ex; }
}
Client Side Sending bytes to server
byte[] fileA;
IPAddress ipAd = IPAddress.Parse("IpAddress");
TcpClient client = new TcpClient(ipAd.ToString(), Port);
NetworkStream stream = client.GetStream();
StreamReader reader = new StreamReader("D:/Users/Public/Pictures/Sample Pictures/06250_2.jpg");
//StreamReader reader = new StreamReader("D:/Users/703132799/Desktop/Foo.txt");
string data = reader.ReadToEnd();
reader.Close();
fileA = System.Text.Encoding.ASCII.GetBytes(data);
int length = 0;
length = fileA.Length;
Console.WriteLine("Sending Buffer Length-" + length);
stream.Write(fileA, 0, fileA.Length);
stream.Flush();
//Thread.Sleep(10000);
Console.ReadLine();
Whole code at server, It is Asynchronous way
static void Main(string[] args)
{
StartServer();
}
private static TcpListener _listener;
public static void StartServer()
{
IPAddress localIPAddress = IPAddress.Parse("IPAddress");
IPEndPoint ipLocal = new IPEndPoint(localIPAddress, Port);
_listener = new TcpListener(ipLocal);
_listener.Start();
WaitForClientConnect();
}
private static void WaitForClientConnect()
{
object obj = new object();
_listener.BeginAcceptTcpClient(new System.AsyncCallback(OnClientConnect), obj);
Console.ReadLine();
}
private static void OnClientConnect(IAsyncResult asyn)
{
try
{
TcpClient clientSocket = default(TcpClient);
clientSocket = _listener.EndAcceptTcpClient(asyn);
HandleClientRequest clientReq = new HandleClientRequest(clientSocket);
clientReq.StartClient();
}
catch (Exception ex)
{
throw ex;
}
WaitForClientConnect();
}
}
public class HandleClientRequest
{
TcpClient _clientSocket;
NetworkStream _networkStream = null;
public HandleClientRequest(TcpClient clientConnected)
{
this._clientSocket = clientConnected;
}
public void StartClient()
{
_networkStream = _clientSocket.GetStream();
WaitForRequest();
}
public void WaitForRequest()
{
byte[] buffer = new byte[_clientSocket.ReceiveBufferSize];
_networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer);
}
private void ReadCallback(IAsyncResult result)
{
string sRecMsgAsciiWithHex = string.Empty;
NetworkStream networkStream = _clientSocket.GetStream();
ReadFully(networkStream, 65536);
}
public static void ReadFully(NetworkStream stream, int initialLength)
{
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[initialLength];
int chunk;
try
{
int read = -1;
int totread = 0;
using (var fileStream = File.OpenWrite("C:\\Foo.txt"))
{
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
totread += read;
Console.WriteLine("Toatal Read" + totread);
fileStream.Write(buffer, 0, buffer.Length);
//string filePath = "C:\\Foo.txt";
//StreamWriter objWriter;
//using (objWriter = File.AppendText(filePath))
//{
// objWriter.WriteLine(totread);
// objWriter.Flush();
// objWriter.Close();
//}
}
}
Console.WriteLine("Toatal Read" + totread);
}
catch (IOException e)
{ throw; }
}
UPDATE:
You're not closing the connection - simple as that; if you're interested I can post a full code sample.
Put client.Close(); after the stream.Flush() in the end of "Client Side Sending bytes to server" routine.
All the code:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
StartServer();
// test sending
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(IPAddress.Parse("127.0.0.1"), 4000);
// get a file here instead
byte[] longBuffer = new byte[3824726];
byte[] buffer = new byte[4096];
// emulated stream over emulated buffer
using (var stream = new MemoryStream(longBuffer, false)) {
while (true) {
int read = stream.Read(buffer, 0, buffer.Length);
if (read <= 0) {
break;
}
for (int sendBytes = 0; sendBytes < read; sendBytes += client.Send(buffer, sendBytes, read - sendBytes, SocketFlags.None)) {
}
}
}
// the tricky part ;)
client.Close();
Console.In.ReadLine();
_stop = true;
}
private static TcpListener _listener;
private static volatile bool _stop = false;
private sealed class Client : IDisposable {
public Socket Socket { get; private set; }
public byte[] Buffer { get; private set; }
public FileStream WriteStream { get; private set; }
public Client(Socket socket) {
if (socket == null) {
throw new ArgumentNullException("socket");
}
Socket = socket;
Buffer = new byte[4096];
WriteStream = File.OpenWrite(#"c:\foo" + Guid.NewGuid().ToString("N") + ".txt");
}
public void Close() {
if (Socket != null) {
Socket.Close();
}
if (WriteStream != null) {
WriteStream.Close();
}
}
public void Dispose() {
Close();
}
}
public static void StartServer() {
IPAddress localIPAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint ipLocal = new IPEndPoint(localIPAddress, 4000);
_listener = new TcpListener(ipLocal);
_listener.Start();
_listener.BeginAcceptSocket(BeginAcceptSocketCallback, null);
}
private static void BeginAcceptSocketCallback(IAsyncResult asyn) {
Client client = null;
try {
client = new Client(_listener.EndAcceptSocket(asyn));
client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, SocketFlags.None, BeginReceiveCallback, client);
} catch (ObjectDisposedException e) {
HandleSocketFailure(client, e, "BeginAcceptSocketCallback failure", false);
} catch (SocketException e) {
HandleSocketFailure(client, e, "BeginAcceptSocketCallback failure", false);
} catch (Exception e) {
HandleSocketFailure(client, e, "BeginAcceptSocketCallback failure", true);
}
if (!_stop) {
_listener.BeginAcceptSocket(BeginAcceptSocketCallback, null);
}
}
private static void BeginReceiveCallback(IAsyncResult result) {
var client = (Client)result.AsyncState;
try {
int bytesRead = client.Socket.EndReceive(result);
if (bytesRead > 0) {
client.WriteStream.Write(client.Buffer, 0, bytesRead);
client.Socket.BeginReceive(client.Buffer, 0, client.Buffer.Length, SocketFlags.None, BeginReceiveCallback, client);
} else {
client.Close();
}
} catch (SocketException e) {
HandleSocketFailure(client, e, "BeginReceiveCallback failure", false);
} catch (ObjectDisposedException e) {
HandleSocketFailure(client, e, "BeginReceiveCallback failure", false);
} catch (Exception e) {
HandleSocketFailure(client, e, "BeginReceiveCallback failure", true);
}
}
private static void HandleSocketFailure(Client client, Exception exception, string message, bool isFatal) {
// log exception as well at least for isFatal = true
if (client != null) {
client.Close();
}
}
}
}

Determine end of message in socket stream

I have a project with a server and a client using asynchronous socket connections.
I want to transmit an object from server to client. Unfortunately I have the problem, that sometimes the object isn't fully transmitted in one go. Therefore I need a way to determine when an object was fully transmitted. So I added a four-byte-head to the data transmitted to tell, how long the stream will be.
Server
private void Send(Socket handler, Packet packet)
{
byte[] byteData = ByteHelper.Serialize(packet).Data;
byte[] byteDataLength = BitConverter.GetBytes(byteData.Length);
byte[] transmissionData = new byte[byteDataLength.Length + byteData.Length];
byteDataLength.CopyTo(transmissionData, 0);
byteData.CopyTo(transmissionData, byteDataLength.Length);
if (debug)
{
Status = "Sending "+packet.Type+"-packet to client.";
}
try
{
handler.BeginSend(transmissionData, 0, transmissionData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch (Exception ex)
{
Status = "[EXCEPTION]" + ex.Message.ToString();
}
}
The client receives the stream and evaluates the first four bytes to create a StateObject which has the right size. But I have the feeling that this is not really a good way to solve my problem. Is there a better way to do this?
Client
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
try
{
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
do
{
state = AdjustState(state);
if (state != null)
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
}
else
{
receiveDone.Set();
}
}
while (state != null && state.tempBuffer.Length >= state.bufferSize);
if (state != null)
{
client.BeginReceive(state.tempBuffer, 0, state.tempBuffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (Exception ex)
{
MessageBox.Show("ReceiveCallback: " + ex.ToString(), "Client-Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static StateObject AdjustState(StateObject state)
{
StateObject tempState = state;
if (tempState.tempBuffer.Length >= 4)
{
byte[] sizeBytes = tempState.tempBuffer.Take(4).ToArray();
int bufferSize = BitConverter.ToInt32(sizeBytes, 0);
if (bufferSize == 0)
{
return null;
}
byte[] temp = tempState.tempBuffer.Skip(4).ToArray();
Socket tempSocket = tempState.workSocket;
tempState = new StateObject(bufferSize);
tempState.BufferSet();
if (temp.Length >= bufferSize)
{
tempState.buffer = temp.Take(bufferSize).ToArray();
tempState.tempBuffer = temp.Skip(bufferSize).ToArray();
}
tempState.workSocket = tempSocket;
}
return tempState;
}
Solution
Thanks to usr I've changed the bytesRead-Part in the ReceiveCallbackCode of the client to this. It seems to work now.
if (bytesRead > 0)
{
if (!state.bufferSet)
{
state = AdjustState(state);
client.BeginReceive(state.buffer, 0, state.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
else
{
client.BeginReceive(state.buffer, state.buffer.Length, state.bufferSize - state.buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
You are not making use of the return value from EndReceive (bytesRead). It signals how many bytes were received.
And in case bytesRead == 0 you just do nothing which is probably not a proper response to the connection having ended.
And then, there is this unsynchronized busy-loop:
while (state != null && state.tempBuffer.Length >= state.bufferSize);
That's going to burn one CPU core for each client connection. Must solve this differently.

Categories

Resources