I am currently tyring to create a Multi threading and async tcp server that implements the Tcpl listener
Current the server is working as intended as i am able to send data to the server an transmit data to the client with out any problems
However after i have sent data to the server and then sent data back to the client, when the client sends data back to the server again the server is unabe to pick up the data
I have tried for days to find an answer to this problem however with no luck
Here is the code that i am currently using in the server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using System.IO;
namespace MyTcpAsyncClass
{
public class StateObject
{
public TcpClient MyTcpClient = null;
public NetworkStream MyNetworkStream = null;
public const int MyBufferSize = 1024;
public byte[] MyBuffer = new byte[MyBufferSize];
public string RequestString = "";
public StringBuilder MyStringBuilder = new StringBuilder();
char[] RequestChars; // Char array of Request
const char STX = (char)0x02; // Start Character
const char FTX = (char)0x03; // Finish Character
public void Dispose()
{
try
{
MyTcpClient.Close();
MyNetworkStream.Close();
MyNetworkStream.Dispose();
}
catch (Exception ex)
{
MessageBox.Show("Message:\n" + ex.Message + "\n\nStacktrace:\n" + ex.StackTrace);
}
}
}
public static class AsyncServerFunctions
{
private static int mPort = 0;
private static ManualResetEvent MyManualResetEvent = new ManualResetEvent(false);
public static void StartListening()
{
//Catch to Tcp Client Connection
try
{
//Get the database connection
//MyReaderWriterLockSlim.EnterReadLock();
LoadSettings();
//MyReaderWriterLockSlim.ExitReadLock();
TcpListener MyTcpListener = new TcpListener(IPAddress.Any, mPort);
MyTcpListener.Start();
while (true)
{
//Set the event to nonsignaled state
MyManualResetEvent.Reset();
//Start an asynchronous TcpListener to listen for a connection
MyTcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, MyTcpListener);
//Wait until a connection is made before continuing
MyManualResetEvent.WaitOne();
}
MyTcpListener.Stop();
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void AcceptTcpClientCallback(IAsyncResult result)
{
try
{
//BeginAcceptTcpClientCallback
//Signal the main thread to continue
MyManualResetEvent.Set();
//Get the TcpClientNetworkStream:
TcpListener MyTcpListener = (TcpListener)result.AsyncState;
//Finish Async Get Client Process
TcpClient MyTcpClient = MyTcpListener.EndAcceptTcpClient(result);
StateObject MyStateObject = new StateObject();
MyStateObject.MyTcpClient = MyTcpClient;
MyStateObject.MyNetworkStream = MyTcpClient.GetStream();
//Begin Async read from the NetworkStream
MyStateObject.MyNetworkStream.BeginRead(MyStateObject.MyBuffer, 0, StateObject.MyBufferSize, new AsyncCallback(BeginReadCallback), MyStateObject);
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void BeginReadCallback(IAsyncResult result)
{
StateObject MyStateObject = (StateObject)result.AsyncState;
NetworkStream MyNetworkStream = MyStateObject.MyNetworkStream;
string MyRequestString = "";
try
{
//Get Request Data here
if (MyStateObject.MyBuffer.Length > 0)
{
//Store the data recived
MyStateObject.MyStringBuilder.Clear();
MyStateObject.MyStringBuilder.Append(Encoding.ASCII.GetString(MyStateObject.MyBuffer));
//Get the stored Request string
MyRequestString = MyStateObject.MyStringBuilder.ToString();
//Record the string recived
DatabaseFunctions.AddMessageLog("String Recived (BeginReadCallback): " + MyRequestString);
//Remove the first and last character
MyRequestString = CleanString(MyRequestString);
//Record the Request String
DatabaseFunctions.AddMessageLog("Request String Recived:" + MyRequestString);
//Get the Message Identifier
string MessageIdentifier = "";
MessageIdentifier = MyRequestString.Substring(0, 2);
switch (MessageIdentifier)
{
case "value":
SendResponse(MyStateObject, StartUp(MessageIdentifier, MyRequestString));
SendResponse(MyStateObject, SendTransactionStart(MessageIdentifier, MyAmount));
GetResponse(MyStateObject);
break;
default:
//***Default Case***
SendResponse(MyStateObject, DefaultCase(MyRequestString));
break;
}
//Dispose of the connection
MyStateObject.Dispose();
}
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
try
{
MyStateObject.Dispose();
}
catch
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
}
private static void SendResponse(StateObject pMyStateObject, string pResponseString)
{
try
{
//Send a response to the client
//Get bytes from string sent
byte[] MyResponseBytes = Encoding.ASCII.GetBytes(pResponseString);
//Get the network stream
NetworkStream MyNetworkStream = pMyStateObject.MyNetworkStream;
//Call SendResponseCallback
MyNetworkStream.BeginWrite(MyResponseBytes, 0, MyResponseBytes.Length, new AsyncCallback(SendResponseCallback), pMyStateObject);
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void GetResponse(StateObject pStateObject)
{
//This will run a new AsyncCallback To get the response from the client
NetworkStream MyNetworkStream = pStateObject.MyNetworkStream;
pStateObject.MyBuffer = new byte[1024];
MyNetworkStream.BeginRead(pStateObject.MyBuffer, 0, pStateObject.MyBuffer.Length, new AsyncCallback(BeginReadCallback), pStateObject);
}
private static void SendResponseCallback(IAsyncResult result)
{
try
{
//End the send procedure
StateObject MyStateObject = (StateObject)result.AsyncState;
NetworkStream MyNetworkStream = MyStateObject.MyNetworkStream;
MyNetworkStream.Flush();
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace)
}
}
private static void ShowExceptionMessage(string pMessage, string pStacktrace)
{
MessageBox.Show("Message:\n" + pMessage + "\n\nStacktrace:\n" + pStacktrace);
}
private static void AddErrorLog(string pMessage, string pStackTrace)
{
DatabaseFunctions.AddMessageLog("Message:" + pMessage + "; Stacktrace:" + pStackTrace);
}
}
}
Thanks All
You should call BeginAcceptTcpClient in AcceptTcpClientCallback also. You don't accept any new connection after the first one.
In your BeginReadCallback function you dispose off the object you have used to invoke BeginRead try running the code without dispose function and you are only calling the GetRespone function in switch condition, try calling BeginRead in your BeginReadCallback function.
Related
I have 2 Application in a visual studio Windows Forms App(.Net Framework 4) The names of my two programs are:
IpServer
IpClient
My problem is that I do not know what to do that when the IpClient Application closes or stops or the IpServer Application shows a message in messagebox.show("Client Is dissconnect")
IpServer Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace IpServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TcpListener tcplist;
Socket s;
private void init()
{
IPAddress ip = IPAddress.Parse("127.0.0.1");
tcplist = new TcpListener(ip,5050);
tcplist.Start();
while (true)
{
s = tcplist.AcceptSocket();
Thread t = new Thread(new ThreadStart(replay));
t.IsBackground = true;
t.Start();
}
}
private void replay()
{
Socket sc = s;
NetworkStream ns = new NetworkStream(sc);
StreamReader reader = new StreamReader(ns);
StreamWriter writer = new StreamWriter(ns);
string str = "";
string response = "";
try { str = reader.ReadLine(); }
catch { str = "error"; }
if (str == "register")
{
MessageBox.Show("ok");
}
response = "registeredSucss,";
writer.WriteLine(response);
writer.Flush();
ns.Close();
sc.Close();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(init));
t.IsBackground = true;
t.Start();
MessageBox.Show("Server run!!");
button1.Enabled = false;
}
and IpClient Code :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace IpClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TcpClient tcp;
NetworkStream ns;
StreamReader reader;
StreamWriter writer;
string str = "";
private void button1_Click(object sender, EventArgs e)
{
try
{
tcp = new TcpClient("127.0.0.1",5050);
tcp.ReceiveBufferSize = 25000;
tcp.NoDelay = true;
ns = tcp.GetStream();
reader = new StreamReader(ns);
writer = new StreamWriter(ns);
writer.WriteLine("register");
writer.Flush();
str = reader.ReadLine();
string[] strsplit = null;
strsplit = str.Split(',');
if (strsplit[0] != "registeredSucss")
{
MessageBox.Show("Not connected");
}
else
{
MessageBox.Show("Your connected");
}
}
catch
{
MessageBox.Show("error");
}
}
I wrote a complete example for you.
You can modify it according to your needs.
Simply connecting the client to the server without sending or receiving messages will not disconnect.
In the server and the client, there is a thread that continuously calls the receive function, and sends a message when the connection is disconnected.
byte[] buffer = new byte[1024 * 1024 * 2];
int length = socket.Receive(buffer);
if (length == 0) {
///Write the desired operation
}
"Disconnect when closing the window" uses the formclosing event:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
}
This is the control diagram used by the two windows:
IpClient:
IpServe:
This is the code for the two windows:
IpClient:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace IpClient {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
Socket socket;//The socket responsible for the connection
private void ConnectB_Click(object sender, EventArgs e) {
//Determine whether to request a connection repeatedly
try {
Log("Connected " + socket.LocalEndPoint.ToString() + "\nPlease do not request the connection repeatedly");
} catch {
//Determine whether the input is wrong
try {
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Create IP address and port number;
IPAddress ip = IPAddress.Parse(Ipbox.Text);
int port = Convert.ToInt32(PortBox.Text);
IPEndPoint iPEndPoint = new IPEndPoint(ip, port);
//Determine whether you can connect to the server
try {
socket.Connect(iPEndPoint);
Log("Connected " + socket.LocalEndPoint.ToString());
//Start receiving data thread
Thread th = new Thread(receive);
th.IsBackground = true;
th.Start();
} catch {
Log("Port is not open");
}
} catch {
socket = null;
Log("Input error");
}
}
}
private void Log(string str) {
ClientLog.AppendText(str + "\r\n");
}
private void receive() {
while (true) {
//Determine whether the data can be received
try {
byte[] buffer = new byte[1024 * 1024 * 2];
int length = socket.Receive(buffer);
if (length == 0) {
Log("Port is not open");
CloseSocket(socket);
socket = null;
break;
}
string txt = Encoding.UTF8.GetString(buffer, 0, length);
Log(socket.RemoteEndPoint + ":\r\t" + txt);
} catch {
break;
}
}
}
private void Form1_Load(object sender, EventArgs e) {
Control.CheckForIllegalCrossThreadCalls = false;
}
private void CloseB_Click(object sender, EventArgs e) {
if (socket != null) {
CloseSocket(socket);
socket = null;
Log("Connection closed");
} else {
Log("Not connected");
}
}
private void SendB_Click(object sender, EventArgs e) {
try {
string txt = SendText.Text;
byte[] buffer = Encoding.ASCII.GetBytes(txt);//ascii encoding
socket.Send(buffer);
} catch {
Log("Not connected");
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
if (socket != null) {
CloseSocket(socket);
socket = null;
}
}
//Disconnect socket
private void CloseSocket(Socket o) {
try {
o.Shutdown(SocketShutdown.Both);
o.Disconnect(false);
o.Close();
} catch {
Log("error");
}
}
}
}
IpServer:
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace IpServer {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
Socket socketSend;//Socket responsible for communication
Socket socketListener;//Socket responsible for monitoring
Dictionary<string, Socket> dictionary = new Dictionary<string, Socket>();//Store the connected Socket
private void listnerB_Click(object sender, EventArgs e) {
//Create a listening socket
//SocketType.Stream streaming corresponds to the tcp protocol
//Dgram, datagram corresponds to UDP protocol
socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try {
//Create IP address and port number;
IPAddress ip = IPAddress.Parse(Ipbox.Text);
int port = Convert.ToInt32(PortBox.Text);
IPEndPoint iPEndPoint = new IPEndPoint(ip, port);
//Let the listening socket bind the ip and port number
socketListener.Bind(iPEndPoint);
Log("Listen successfully" + ip + "\t" + port);
//Set up the listening queue
socketListener.Listen(10);//Maximum number of connections at a time
Thread thread = new Thread(Listen);
thread.IsBackground = true;
thread.Start(socketListener);
} catch {
Log("Failed to listen");
}
}
//Use threads to receive data
private void Listen(object o) {
Socket socket = o as Socket;
while (true) {
//The socket responsible for monitoring is used to receive client connections
try {
//Create a socket responsible for communication
socketSend = socket.Accept();
dictionary.Add(socketSend.RemoteEndPoint.ToString(), socketSend);
clientCombo.Items.Add(socketSend.RemoteEndPoint.ToString());
clientCombo.SelectedIndex = clientCombo.Items.IndexOf(socketSend.RemoteEndPoint.ToString());
Log("Connected " + socketSend.RemoteEndPoint.ToString());
//Start a new thread to receive information from the client
Thread th = new Thread(receive);
th.IsBackground = true;
th.Start(socketSend);
} catch {
continue;
}
}
}
//The server receives the message from the client
private void receive(object o) {
Socket socketSend = o as Socket;
while (true) {
//Try to connect to the client
try {
//After the client connects successfully, the server receives the message from the client
byte[] buffer = new byte[1024 * 1024 * 2];//2M大小
//Number of valid bytes received
int length = socketSend.Receive(buffer);
if (length == 0) {
string tmpIp = socketSend.RemoteEndPoint.ToString();
Log(tmpIp + " Offline");
clientCombo.Items.Remove(tmpIp);
//Try to delete the connection information
try {
clientCombo.SelectedIndex = 0;
} catch {
clientCombo.Text = null;
}
CloseSocket(dictionary[tmpIp]);
dictionary.Remove(tmpIp);
break;
}
string str = Encoding.ASCII.GetString(buffer, 0, length);
Log(socketSend.RemoteEndPoint.ToString() + "\n\t" + str);
} catch {
break;
}
}
}
private void Log(string str) {
ServerLog.AppendText(str + "\r\n");
}
private void Form1_Load(object sender, EventArgs e) {
//Cancel errors caused by cross-thread calls
Control.CheckForIllegalCrossThreadCalls = false;
}
//Send a message
private void SendB_Click(object sender, EventArgs e) {
string txt = SendText.Text;
byte[] buffer = Encoding.UTF8.GetBytes(txt);
try {
string ip = clientCombo.SelectedItem.ToString();//Get the selected ip address
Socket socketsend = dictionary[ip];
socketsend.Send(buffer);
} catch{
Log("Transmission failed");
}
}
private void Close_Click(object sender, EventArgs e) {
try {
try {
string tmpip = socketSend.RemoteEndPoint.ToString();
CloseSocket(dictionary[tmpip]);
dictionary.Remove(tmpip);
clientCombo.Items.Remove(tmpip);
try {
clientCombo.SelectedIndex = 0;
} catch {
clientCombo.Text = null;
}
socketSend.Close();
Log(socketSend.RemoteEndPoint.ToString() + "Offline");
socketListener.Close();
Log("Listener is closed");
} catch{
socketListener.Close();
Log("Listener is closed");
}
} catch {
Log("close error");
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
try {
try {
string tmpip = socketSend.RemoteEndPoint.ToString();
CloseSocket(dictionary[tmpip]);
dictionary.Remove(tmpip);
clientCombo.Items.Remove(tmpip);
try {
clientCombo.SelectedIndex = 0;
} catch {
clientCombo.Text = null;
}
socketSend.Close();
socketListener.Close();
} catch {
socketListener.Close();
}
} catch {
}
}
private void CloseSocket(Socket o) {
try {
o.Shutdown(SocketShutdown.Both);
o.Disconnect(false);
o.Close();
} catch {
Log(o.ToString() + "error");
}
}
}
}
OutPut:
Closing the window causes disconnection:
Disconnect manually:
Transfer data:
If you have any question about my code, please add a comment below.
I'm trying to implement wrapper class which will simply connect to TCP server and wait for data. Once data submitted from server - I will receive this data and pass it onto subscribers of my class.
All this works. Now I want to add external functionality to "reset" this class on a timer (force reconnect every so often) to keep connection alive. My idea is that Init method can be called as many times as needed to get socket reset. However, I do get various exceptions with this.
Class code:
namespace Ditat.GateControl.Service.InputListener
{
using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class BaseTCPSocketListener : IInputListener
{
#region Events/Properties
public event EventHandler<Exception> OnError;
public event EventHandler<string> OnDataReceived;
private string host;
private int port;
private int delayToClearBufferSeconds = 5;
private TcpClient client;
private readonly byte[] buffer = new byte[1024];
/// <summary>
/// Will accumulate data as it's received
/// </summary>
private string DataBuffer { get; set; }
/// <summary>
/// Store time of last data receipt. Need this in order to purge data after delay
/// </summary>
private DateTime LastDataReceivedOn { get; set; }
#endregion
public BaseTCPSocketListener()
{
// Preset all entries
this.LastDataReceivedOn = DateTime.UtcNow;
this.DataBuffer = string.Empty;
}
public void Init(string config)
{
// Parse info
var bits = config.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
this.host = bits[0];
var hostBytes = this.host.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var hostIp = new IPAddress(new[] { byte.Parse(hostBytes[0]), byte.Parse(hostBytes[1]), byte.Parse(hostBytes[2]), byte.Parse(hostBytes[3]) });
this.port = int.Parse(bits[1]);
this.delayToClearBufferSeconds = int.Parse(bits[2]);
// Close open client
if (this.client?.Client != null)
{
this.client.Client.Disconnect(true);
this.client = null;
}
// Connect to client
this.client = new TcpClient();
if (!this.client.ConnectAsync(hostIp, this.port).Wait(2500))
throw new Exception($"Failed to connect to {this.host}:{this.port} in allotted time");
this.EstablishReceiver();
}
protected void DataReceived(IAsyncResult result)
{
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
bytesCount = this.client.Client.EndReceive(result);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
// No data received, establish receiver and return
if (bytesCount == 0)
{
this.EstablishReceiver();
return;
}
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(this.buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
private void EstablishReceiver()
{
try
{
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, this.DataReceived, this.buffer);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
private void RaiseOnErrorToClient(Exception ex)
{
if (this.OnError == null) return;
foreach (Delegate d in this.OnError.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, ex);
}
else
{
syncer.BeginInvoke(d, new object[] { this, ex });
}
}
}
private void RaiseOnDataReceivedToClient(string data)
{
if (this.OnDataReceived == null) return;
foreach (Delegate d in this.OnDataReceived.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, data);
}
else
{
syncer.BeginInvoke(d, new object[] { this, data });
}
}
}
}
}
Client code (under button click on form)
private void ListenBaseButton_Click(object sender, EventArgs e)
{
if (this.bsl == null)
{
this.bsl = new BaseTCPSocketListener();
this.bsl.OnDataReceived += delegate (object o, string s)
{
this.DataTextBox.Text += $"Base: {DateTime.Now} - {s}" + Environment.NewLine;
};
this.bsl.OnError += delegate (object o, Exception x)
{
this.DataTextBox.Text += $"Base TCP receiver error: {DateTime.Now} - {x.Message}" + Environment.NewLine;
};
}
try
{
this.bsl.Init("192.168.33.70|10001|10");
this.DataTextBox.Text += "BEGIN RECEIVING BSL data --------------------------" + Environment.NewLine;
}
catch (Exception exception)
{
this.DataTextBox.Text += $"ERROR CONNECTING TO BSL ------------{exception.Message}" + Environment.NewLine;
}
}
Exceptions I get. First exception when button clicked 2nd time in from handler in DataReceived
The IAsyncResult object was not returned from the corresponding
asynchronous method on this class.
On following clicks I get exception from handler in EstablishReceiver
A request to send or receive data was disallowed because the socket is
not connected and (when sending on a datagram socket using a sendto
call) no address was supplied
How do I properly ensure socket closed and re-opened?
The IAsyncResult object was not returned from the corresponding
asynchronous method on this class.
This is a well known problem that happens when data callback (DataReceived()) is called for previous socket. In this case you will call Socket.EndReceive() with incorrect instance of IAsyncResult which throws above exception.
Asynchronous Client Socket Example contains possible workaround for this problem: store socket on which BeginReceive() was called in state object which is then passed to DataReceived callback:
StateObject class
public class StateObject
{
public Socket Socket { get; set; }
public byte[] Buffer { get; } = new byte[1024];
public StateObject(Socket socket)
{
Socket = socket;
}
}
EstablishReceiver() method:
private void EstablishReceiver()
{
try
{
var state = new StateObject(client.Client);
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, this.DataReceived, state);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
DataReceived() method:
protected void DataReceived(IAsyncResult result)
{
var state = (StateObject) result.AsyncState;
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
SocketError errorCode;
bytesCount = state.Socket.EndReceive(result, out errorCode);
if (errorCode != SocketError.Success)
{
bytesCount = 0;
}
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
if (bytesCount > 0)
{
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(state.Buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
}
A request to send or receive data was disallowed because the socket is
not connected and (when sending on a datagram socket using a sendto
call) no address was supplied
Above DataReceived() method also contains the fix for the second exception. Exception is caused by calling BeginReceive() (from EstablishReceiver()) on disconnected socket. You should not call BeginReceive() on a socket if previous read brought 0 bytes.
First of all, you're closing the socket being held by the TcpClient, but not disposing the client itself. Try the following:
// Close open client
this.client?.Close(); // Disposes and releases resources
this.client = null;
The issue is that DataReceived will be called when you close the client. You simply need to identify to the method that it should not do anything because you have deliberately ended the process. You could just add a bool:
private bool ignoreCallback;
public void Init(string config)
{
// Parse info
var bits = config.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
this.host = bits[0];
var hostBytes = this.host.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var hostIp = new IPAddress(new[] { byte.Parse(hostBytes[0]), byte.Parse(hostBytes[1]), byte.Parse(hostBytes[2]), byte.Parse(hostBytes[3]) });
this.port = int.Parse(bits[1]);
this.delayToClearBufferSeconds = int.Parse(bits[2]);
// Close open client
if (this.client?.Client != null)
{
ignoreCallback = true;
this.client.Client.Disconnect(true);
this.client = null;
}
// Connect to client
this.client = new TcpClient();
if (!this.client.ConnectAsync(hostIp, this.port).Wait(2500))
throw new Exception($"Failed to connect to {this.host}:{this.port} in allotted time");
this.EstablishReceiver();
}
protected void DataReceived(IAsyncResult result)
{
if (ignoreCallback)
{
ignoreCallback = false;
return;
}
...
I'm trying to build a command line chat room where the server is handling the connections and repeating input from one client back to all the other clients.
Currently the server is able to take in input from multiple clients, but can only send information back to those clients individually. I think my problem is that each connection is being handled on an individual thread. How would I allow for the threads to communicate with each other or be able to send data to each thread?
Server code:
namespace ConsoleApplication
{
class TcpHelper
{
private static object _lock = new object();
private static List<Task> _connections = new List<Task>();
private static TcpListener listener { get; set; }
private static bool accept { get; set; } = false;
private static Task StartListener()
{
return Task.Run(async () =>
{
IPAddress address = IPAddress.Parse("127.0.0.1");
int port = 5678;
listener = new TcpListener(address, port);
listener.Start();
Console.WriteLine($"Server started. Listening to TCP clients at 127.0.0.1:{port}");
while (true)
{
var tcpClient = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client has connected");
var task = StartHandleConnectionAsync(tcpClient);
if (task.IsFaulted)
task.Wait();
}
});
}
// Register and handle the connection
private static async Task StartHandleConnectionAsync(TcpClient tcpClient)
{
// start the new connection task
var connectionTask = HandleConnectionAsync(tcpClient);
// add it to the list of pending task
lock (_lock)
_connections.Add(connectionTask);
// catch all errors of HandleConnectionAsync
try
{
await connectionTask;
}
catch (Exception ex)
{
// log the error
Console.WriteLine(ex.ToString());
}
finally
{
// remove pending task
lock (_lock)
_connections.Remove(connectionTask);
}
}
private static async Task HandleConnectionAsync(TcpClient client)
{
await Task.Yield();
{
using (var networkStream = client.GetStream())
{
if (client != null)
{
Console.WriteLine("Client connected. Waiting for data.");
StreamReader streamreader = new StreamReader(networkStream);
StreamWriter streamwriter = new StreamWriter(networkStream);
string clientmessage = "";
string servermessage = "";
while (clientmessage != null && clientmessage != "quit")
{
clientmessage = await streamreader.ReadLineAsync();
Console.WriteLine(clientmessage);
servermessage = clientmessage;
streamwriter.WriteLine(servermessage);
streamwriter.Flush();
}
Console.WriteLine("Closing connection.");
networkStream.Dispose();
}
}
}
}
public static void Main(string[] args)
{
// Start the server
Console.WriteLine("Hit Ctrl-C to close the chat server");
TcpHelper.StartListener().Wait();
}
}
}
Client Code:
namespace Client2
{
public class Program
{
private static void clientConnect()
{
TcpClient socketForServer = new TcpClient();
bool status = true;
string userName;
Console.Write("Input Username: ");
userName = Console.ReadLine();
try
{
IPAddress address = IPAddress.Parse("127.0.0.1");
socketForServer.ConnectAsync(address, 5678);
Console.WriteLine("Connected to Server");
}
catch
{
Console.WriteLine("Failed to Connect to server{0}:999", "localhost");
return;
}
NetworkStream networkStream = socketForServer.GetStream();
StreamReader streamreader = new StreamReader(networkStream);
StreamWriter streamwriter = new StreamWriter(networkStream);
try
{
string clientmessage = "";
string servermessage = "";
while (status)
{
Console.Write(userName + ": ");
clientmessage = Console.ReadLine();
if ((clientmessage == "quit") || (clientmessage == "QUIT"))
{
status = false;
streamwriter.WriteLine("quit");
streamwriter.WriteLine(userName + " has left the conversation");
streamwriter.Flush();
}
if ((clientmessage != "quit") && (clientmessage != "quit"))
{
streamwriter.WriteLine(userName + ": " + clientmessage);
streamwriter.Flush();
servermessage = streamreader.ReadLine();
Console.WriteLine("Server:" + servermessage);
}
}
}
catch
{
Console.WriteLine("Exception reading from the server");
}
streamreader.Dispose();
networkStream.Dispose();
streamwriter.Dispose();
}
public static void Main(string[] args)
{
clientConnect();
}
}
}
The main thing wrong in your code is that you make no attempt to send data received from one client to the other connected clients. You have the _connections list in your server, but the only thing stored in the list are the Task objects for the connections, and you don't even do anything with those.
Instead, you should maintain a list of the connections themselves, so that when you received a message from one client, you can then retransmit that message to the other clients.
At a minimum, this should be a List<TcpClient>, but because you are using StreamReader and StreamWriter, you'll want to initialize and store those objects in the list as well. In addition, you should include a client identifier. One obvious choice for this would be the name of the client (i.e. what the user enters as their name), but your example doesn't provide any mechanism in the chat protocol to transmit that identification as part of the connection initialization, so in my example (below) I just use a simple integer value.
There are some other irregularities in the code you posted, such as:
Starting a task in a brand new thread, just to execute a few statements that get you to the point of initiating an asynchronous operation. In my example, I simply omit the Task.Run() part of the code, as it's not needed.
Checking the connection-specific task when it's returned for IsFaulted. Since it's unlikely any I/O will actually have occurred by the time this Task object is returned, this logic has very little use. The call to Wait() will throw an exception, which will propagate to the main thread's Wait() call, terminating the server. But you don't terminate the server in the event of any other error, so it's not clear why you'd want to do that here.
There's a spurious call to Task.Yield(). I have no idea what you're trying to accomplish there, but whatever it is, that statement isn't useful. I simply removed it.
In your client code, you only attempt to receive data from the server when you've sent data. This is very wrong; you want clients to be responsive and receive data as soon as it's sent to them. In my version, I included a simple little anonymous method that is called immediately to start a separate message-receiving loop that will execute asynchronously and concurrently with the main user input loop.
Also in the client code, you were sending the "…has left…" message after the "quit" message that would cause the server to close the connection. This means that the server would never actually receive the "…has left…" message. I reversed the order of the messages so that "quit" is always the last thing the client ever sends.
My version looks like this:
Server:
class TcpHelper
{
class ClientData : IDisposable
{
private static int _nextId;
public int ID { get; private set; }
public TcpClient Client { get; private set; }
public TextReader Reader { get; private set; }
public TextWriter Writer { get; private set; }
public ClientData(TcpClient client)
{
ID = _nextId++;
Client = client;
NetworkStream stream = client.GetStream();
Reader = new StreamReader(stream);
Writer = new StreamWriter(stream);
}
public void Dispose()
{
Writer.Close();
Reader.Close();
Client.Close();
}
}
private static readonly object _lock = new object();
private static readonly List<ClientData> _connections = new List<ClientData>();
private static TcpListener listener { get; set; }
private static bool accept { get; set; }
public static async Task StartListener()
{
IPAddress address = IPAddress.Any;
int port = 5678;
listener = new TcpListener(address, port);
listener.Start();
Console.WriteLine("Server started. Listening to TCP clients on port {0}", port);
while (true)
{
var tcpClient = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client has connected");
var task = StartHandleConnectionAsync(tcpClient);
if (task.IsFaulted)
task.Wait();
}
}
// Register and handle the connection
private static async Task StartHandleConnectionAsync(TcpClient tcpClient)
{
ClientData clientData = new ClientData(tcpClient);
lock (_lock) _connections.Add(clientData);
// catch all errors of HandleConnectionAsync
try
{
await HandleConnectionAsync(clientData);
}
catch (Exception ex)
{
// log the error
Console.WriteLine(ex.ToString());
}
finally
{
lock (_lock) _connections.Remove(clientData);
clientData.Dispose();
}
}
private static async Task HandleConnectionAsync(ClientData clientData)
{
Console.WriteLine("Client connected. Waiting for data.");
string clientmessage;
while ((clientmessage = await clientData.Reader.ReadLineAsync()) != null && clientmessage != "quit")
{
string message = "From " + clientData.ID + ": " + clientmessage;
Console.WriteLine(message);
lock (_lock)
{
// Locking the entire operation ensures that a) none of the client objects
// are disposed before we can write to them, and b) all of the chat messages
// are received in the same order by all clients.
foreach (ClientData recipient in _connections.Where(r => r.ID != clientData.ID))
{
recipient.Writer.WriteLine(message);
recipient.Writer.Flush();
}
}
}
Console.WriteLine("Closing connection.");
}
}
Client:
class Program
{
private const int _kport = 5678;
private static async Task clientConnect()
{
IPAddress address = IPAddress.Loopback;
TcpClient socketForServer = new TcpClient();
string userName;
Console.Write("Input Username: ");
userName = Console.ReadLine();
try
{
await socketForServer.ConnectAsync(address, _kport);
Console.WriteLine("Connected to Server");
}
catch (Exception e)
{
Console.WriteLine("Failed to Connect to server {0}:{1}", address, _kport);
return;
}
using (NetworkStream networkStream = socketForServer.GetStream())
{
var readTask = ((Func<Task>)(async () =>
{
using (StreamReader reader = new StreamReader(networkStream))
{
string receivedText;
while ((receivedText = await reader.ReadLineAsync()) != null)
{
Console.WriteLine("Server:" + receivedText);
}
}
}))();
using (StreamWriter streamwriter = new StreamWriter(networkStream))
{
try
{
while (true)
{
Console.Write(userName + ": ");
string clientmessage = Console.ReadLine();
if ((clientmessage == "quit") || (clientmessage == "QUIT"))
{
streamwriter.WriteLine(userName + " has left the conversation");
streamwriter.WriteLine("quit");
streamwriter.Flush();
break;
}
else
{
streamwriter.WriteLine(userName + ": " + clientmessage);
streamwriter.Flush();
}
}
await readTask;
}
catch (Exception e)
{
Console.WriteLine("Exception writing to server: " + e);
throw;
}
}
}
}
public static void Main(string[] args)
{
clientConnect().Wait();
}
}
There is still a lot you'll need to work on. You'll probably want to implement proper initialization of chat user names on the server side. At the very least, for real-world code you'd want to do more error checking, and make sure the client ID is generated reliably (if you only want positive ID values, you can't have more than 2^31-1 connections before it rolls back over to 0).
I also made some other minor changes that weren't strictly necessary, such as using the IPAddress.Any and IPAddress.Loopback values instead of parsing strings, and just generally simplifying and cleaning up the code here and there. Also, I'm not using a C# 6 compiler at the moment, so I changed the code where you were using C# 6 features so that it would compile using C# 5 instead.
To do a full-blown chat server, you still have your work cut out for you. But I hope that the above gets you back on the right track.
I had a perfectly fine working console program that uses UdpClient.send to send messages to another program on the localhost (over port 7777). (which oddly enough is an almost identical version this C# script, but running in unity3d, and it has no trouble receiving with the same code).
Now I need to get replies from that program. I added a thread (see bottom) which listens on port 7778 for messages. But I am getting an error when starting saying that:
An existing connection was forcibly closed by the remote host
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Blaster
{
class Blaster
{
UdpClient client;
IPEndPoint outPoint;
IPEndPoint inPoint;
public int oPort = 7777;
public int iPort = 7778;
public string hostName = "localhost";
public int stepNum = 0;
const int rate = 1000;
public System.Timers.Timer clock;
Thread listener;
static void Main(string[] args)
{
Blaster b = new Blaster();
b.run();
}
Blaster()
{
client = new UdpClient();
outPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], oPort);
inPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], iPort);
}
void run()
{
this.stepNum = 0;
listener = new Thread(new ThreadStart(translater));
listener.IsBackground = true;
listener.Start();
Console.WriteLine("Press Enter to do a send loop...\n");
Console.ReadLine();
Console.WriteLine("started at {0:HH:mm:ss.fff}", DateTime.Now);
start();
Console.WriteLine("Press Enter to stop");
Console.ReadLine();
stop();
client.Close();
}
void stop()
{
clock.Stop();
clock.Dispose();
}
void start()
{
clock = new System.Timers.Timer(rate);
clock.Elapsed += send;
clock.AutoReset = true;
clock.Enabled = true;
}
void send(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("sending: {0}", stepNum);
Byte[] sendBytes = Encoding.ASCII.GetBytes(message());
try
{
client.Send(sendBytes, sendBytes.Length, outPoint);
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
}
string message()
{
Packet p = new Packet();
p.id = "car";
p.start = DateTime.Now;
p.x = 1.2f;
p.y = 0.4f;
p.z = 4.5f;
p.step = stepNum++;
string json = JsonConvert.SerializeObject(p);
return json;
}
void translater()
{
Byte[] data = new byte[0];
client.Client.Bind(inPoint);
while (true)
{
try
{
data = client.Receive(ref inPoint);
}
catch (Exception err)
{
Console.WriteLine("Blaster.translater: recieve data error: " + err.Message);
client.Close();
return;
}
string json = Encoding.ASCII.GetString(data);
Console.WriteLine(json);
Packet p = JsonConvert.DeserializeObject<Packet>(json);
}
}
}
}
Ok, I had seen some examples of folks using a single client object for both send and receive (as well as the same port). But then I saw a different port was needed if they were on the same host. Now I see you need a separate udpClient.
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Blaster
{
class Blaster
{
UdpClient client;
IPEndPoint outPoint;
IPEndPoint inPoint;
public int oPort = 7777;
public int iPort = 7778;
public string hostName = "localhost";
public int stepNum = 0;
const int rate = 1000;
public System.Timers.Timer clock;
Thread listener;
static void Main(string[] args)
{
Blaster b = new Blaster();
b.run();
}
Blaster()
{
client = new UdpClient();
outPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], oPort);
inPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], iPort);
}
void run()
{
this.stepNum = 0;
listener = new Thread(new ThreadStart(translater));
listener.IsBackground = true;
listener.Start();
Console.WriteLine("Press Enter to do a send loop...\n");
Console.ReadLine();
Console.WriteLine("started at {0:HH:mm:ss.fff}", DateTime.Now);
start();
Console.WriteLine("Press Enter to stop");
Console.ReadLine();
stop();
client.Close();
}
void stop()
{
clock.Stop();
clock.Dispose();
}
void start()
{
clock = new System.Timers.Timer(rate);
clock.Elapsed += send;
clock.AutoReset = true;
clock.Enabled = true;
}
void send(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("sending: {0}", stepNum);
Byte[] sendBytes = Encoding.ASCII.GetBytes(message());
try
{
client.Send(sendBytes, sendBytes.Length, outPoint);
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
}
string message()
{
Packet p = new Packet();
p.id = "car";
p.start = DateTime.Now;
p.x = 1.2f;
p.y = 0.4f;
p.z = 4.5f;
p.step = stepNum++;
string json = JsonConvert.SerializeObject(p);
return json;
}
void translater()
{
UdpClient server = new UdpClient();
Byte[] data = new byte[0];
server.Client.Bind(inPoint);
while (true)
{
try
{
data = server.Receive(ref inPoint);
}
catch (Exception err)
{
Console.WriteLine("Blaster.translater: recieve data error: " + err.Message);
client.Close();
return;
}
string json = Encoding.ASCII.GetString(data);
Console.WriteLine(json);
Packet p = JsonConvert.DeserializeObject<Packet>(json);
}
}
}
}
Eveyone.
How to resolve the Error code 10054 ? There are some description about this error. Here is my full source code for communication. I want to know whether my code is ok or not.
WSAECONNRESET10054 Connection reset by peer. An existing connection
was forcibly closed by the remote host. This normally results if the
peer application on the remote host is suddenly stopped, the host is
rebooted, the host or remote network interface is disabled, or the
remote host uses a hard close (see setsockopt for more information on
the SO_LINGER option on the remote socket). This error may also result
if a connection was broken due to keep-alive activity detecting a
failure while one or more operations are in progress. Operations that
were in progress fail with WSAENETRESET. Subsequent operations fail
with WSAECONNRESET.
Full Source Code
using System;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using LogManager;
namespace CoreUnitPlatform
{
public class SocketCommCoreUnit
{
#region property
private volatile bool _shouldStop;
private LogWriter log = LogWriter.Instance;
private bool m_bSocketConnected = false;
private Socket m_clientSocket = null;
private SocketCommType m_connectedSockType;
private EventHandlerDataReceived m_evtHandlerDataReceived;
private EventHandlerSocketConnected m_evtHandlerSocketConnected;
private EventHandlerSocketConnectedFailed m_evtHandlerSocketConnectedFailed;
private EventHandlerSocketDisconnected m_evtHandlerSocketDisconnected;
private IPAddress m_IPAddress;
private IPEndPoint m_IPEndPoint;
private int m_portNo;
private Socket m_serverSocket = null;
private Thread m_threadConnectSocket = null;
private string Name = string.Empty;
#endregion
#region constructor
public SocketCommCoreUnit()
{
this.Name = "SocketCommCoreUnit";
Instance();
}
#endregion
#region delegatge
public delegate void EventHandlerDataReceived(string msg);
public delegate void EventHandlerSocketConnected();
public delegate void EventHandlerSocketConnectedFailed();
public delegate void EventHandlerSocketDisconnected();
public enum SocketCommType { SERVER, CLIENT };
public bool SocketConnected
{
get { lock (this) { return m_bSocketConnected; } }
set { lock (this) { m_bSocketConnected = value; } }
}
#endregion
#region public
public void ConnectSocketProc()
{
while (!_shouldStop)
{
try
{
if (SocketConnected == false)
{
if (m_connectedSockType == SocketCommType.SERVER)
{
m_clientSocket = m_serverSocket.Accept(); // If a client is connected, wait for data from client
m_evtHandlerSocketConnected();
SocketConnected = true;
}
else
{
m_clientSocket.Connect(m_IPAddress, m_portNo);
if (m_clientSocket.Connected == true)
{
m_evtHandlerSocketConnected();
SocketConnected = true;
}
}
}
else
{
try
{
byte[] buffer = new byte[1024];
int readBytes = this.m_clientSocket.Receive(buffer);
if (readBytes == 0)
{
this.reConnect();
}
else
{
string received = System.Text.Encoding.ASCII.GetString(buffer);
m_evtHandlerDataReceived(received);
}
}
catch (SocketException sex)
{
if (sex.NativeErrorCode.Equals(10054))
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured [{0}]: MESASGE[{1}]\r\nSOURCE[{2}]\r\nTRACE[{3}]", sex.NativeErrorCode, sex.Message, sex.Source, sex.StackTrace));
this.reConnect();
}
}
}
}
catch
{
m_evtHandlerSocketConnectedFailed();
}
Thread.Sleep(100);
}
}
public void Initialize(string IP, int port, SocketCommType sockType, EventHandlerDataReceived evtHandlerDataReceived, EventHandlerSocketConnected evtHandlerDataConnected, EventHandlerSocketDisconnected evtHandlerSocketDisconnected, EventHandlerSocketConnectedFailed evtHandlerSocketConnectedFailed)
{
m_connectedSockType = sockType;
m_evtHandlerDataReceived = evtHandlerDataReceived;
m_evtHandlerSocketDisconnected = evtHandlerSocketDisconnected;
m_evtHandlerSocketConnected = evtHandlerDataConnected;
m_evtHandlerSocketConnectedFailed = evtHandlerSocketConnectedFailed;
m_portNo = port;
m_IPAddress = IPAddress.Parse(IP);
m_IPEndPoint = new IPEndPoint(m_IPAddress, m_portNo);
if (sockType == SocketCommType.SERVER)
{
OpenServer();
}
else
{
OpenClient();
}
}
public void Instance()
{
}
public void OpenClient()
{
try
{
#if _NO_USE_SOCKET
#else
RunClientSocket();
#endif
}
catch (System.Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured: MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
}
public void OpenServer()
{
try
{
#if _NO_USE_SOCKET
#else
RunServerSocket();
#endif
}
catch (System.Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured: MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
}
public void Release()
{
try
{
if (this.m_clientSocket != null && this.m_clientSocket.Connected)
{
SocketConnected = false;
m_evtHandlerSocketDisconnected();
this.m_clientSocket.Shutdown(SocketShutdown.Both);
this.m_clientSocket.Close();
}
if (m_serverSocket != null)
{
m_serverSocket.Close();
}
if ((m_threadConnectSocket != null) && (m_threadConnectSocket.IsAlive == true))
{
Thread.Sleep(1);
RequestStop();
SocketConnected = false;
m_threadConnectSocket.Abort();
m_threadConnectSocket.Join();
}
}
catch (System.Exception ex)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured: MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
}
public void RequestStop()
{
_shouldStop = true;
}
public void RunClientSocket()
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ConfigureTcpSocket(m_clientSocket, SocketCommType.CLIENT);
m_threadConnectSocket = new Thread(new ThreadStart(ConnectSocketProc));
m_threadConnectSocket.Start();
}
public void RunServerSocket()
{
m_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_serverSocket.Bind(m_IPEndPoint);
m_serverSocket.Blocking = true; // The server socket is working in blocking mode
ConfigureTcpSocket(m_serverSocket, SocketCommType.SERVER);
m_serverSocket.Listen(1);
m_threadConnectSocket = new Thread(new ThreadStart(ConnectSocketProc));
m_threadConnectSocket.Start();
}
public void Send(byte[] msg)
{
#if _NO_USE_SOCKET
#else
if (SocketConnected == false)
{
throw new Exception("SOCKET_NOT_CONNECT_BEFORE_SEND_DATA;");
}
try
{
m_clientSocket.Send(msg);
}
catch (System.Exception ex)
{
SocketConnected = false;
m_evtHandlerSocketDisconnected();
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured: MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", ex.Message, ex.Source, ex.StackTrace));
}
#endif
}
#endregion
#region private
private void ConfigureTcpSocket(Socket tcpSocket, SocketCommType socketCommType)
{
//// Don't allow another socket to bind to this port.
//tcpSocket.ExclusiveAddressUse = true;
//// The socket will linger for 10 seconds after
//// Socket.Close is called.
//tcpSocket.LingerState = new LingerOption(true, 10);
// Disable the Nagle Algorithm for this tcp socket.
tcpSocket.NoDelay = true;
//if (socketCommType == SocketCommType.CLIENT)
//{
// tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, false);
// tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
// //tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 3000);
// //tcpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 3000);
// // Set the receive buffer size to 8k
// tcpSocket.ReceiveBufferSize = 2048;
// // Set the send buffer size to 8k.
// tcpSocket.SendBufferSize = 2048;
//}
//// Set the receive buffer size to 8k
//tcpSocket.ReceiveBufferSize = 1024;
// Set the timeout for synchronous receive methods to
// 1 second (1000 milliseconds.)
//tcpSocket.ReceiveTimeout = 1000;
//// Set the send buffer size to 8k.
//tcpSocket.SendBufferSize = 1024;
// Set the timeout for synchronous send methods
// to 1 second (1000 milliseconds.)
//tcpSocket.SendTimeout = 1000;
//// Set the Time To Live (TTL) to 42 router hops.
//tcpSocket.Ttl = 42;
}
private void ConfigureTcpSocket(Socket tcpSocket)
{
//// Don't allow another socket to bind to this port.
//tcpSocket.ExclusiveAddressUse = true;
//// The socket will linger for 10 seconds after
//// Socket.Close is called.
//tcpSocket.LingerState = new LingerOption(true, 10);
// Disable the Nagle Algorithm for this tcp socket.
tcpSocket.NoDelay = true;
//// Set the receive buffer size to 8k
//tcpSocket.ReceiveBufferSize = 8192;
// Set the timeout for synchronous receive methods to
// 1 second (1000 milliseconds.)
//tcpSocket.ReceiveTimeout = 1000;
//// Set the send buffer size to 8k.
//tcpSocket.SendBufferSize = 8192;
// Set the timeout for synchronous send methods
// to 1 second (1000 milliseconds.)
//tcpSocket.SendTimeout = 1000;
//// Set the Time To Live (TTL) to 42 router hops.
//tcpSocket.Ttl = 42;
}
private void reConnect()
{
try
{
SocketConnected = false;
m_evtHandlerSocketDisconnected();
m_clientSocket.Disconnect(true);
log.AddSystemLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Try Re-Connection..."));
if (m_connectedSockType == SocketCommType.SERVER)
{
}
else
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
}
catch (System.Exception exc)
{
log.AddErrorLog(this.Name, MethodBase.GetCurrentMethod().Name, string.Format("Error Occured: MESASGE[{0}]\r\nSOURCE[{1}]\r\nTRACE[{2}]", exc.Message, exc.Source, exc.StackTrace));
}
}
#endregion
}
}
I made a (IMOHO) nice post about async sockets here, It has some pseudo code about server/client sockets.
Article: Unable to read data correctly from .Net socket in C#
I think the code of Asynchronous example is great.