I am implementing a simulated b/s stock data system. I am using flex and c# for client and server sides. I found flash has a security policy and I handled the policy-file-request in my server code. But seems it doesn't work, because the code jumped out at "socket.Receive(b)" after connection. I've tried sending message on client in the connection handler, in that case the server can receive correct message. But the auto-generated "policy-file-request" can never be received, and the client can get no data sending from server. Here I put my code snippet.
my ActionScript code:
public class StockClient extends Sprite {
private var hostName:String = "192.168.84.103";
private var port:uint = 55555;
private var socket:XMLSocket;
public function StockClient() {
socket = new XMLSocket();
configureListeners(socket);
socket.connect(hostName, port);
}
public function send(data:Object) : void{
socket.send(data);
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.CLOSE, closeHandler);
dispatcher.addEventListener(Event.CONNECT, connectHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.addEventListener(ProgressEvent.SOCKET_DATA, dataHandler);
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
//following testing message can be received, but client can't invoke data handler
//send("<policy-file-request/>");
}
private function dataHandler(event:ProgressEvent):void {
//never fired
trace("dataHandler: " + event);
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function progressHandler(event:ProgressEvent):void {
trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
}
my C# code:
const int PORT_NUMBER = 55555;
const String BEGIN_REQUEST = "begin";
const String END_REQUEST = "end";
const String POLICY_REQUEST = "<policy-file-request/>\u0000";
const String POLICY_FILE = "<?xml version=\"1.0\"?>\n" +
"<!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\">\n" +
"<cross-domain-policy> \n" +
" <allow-access-from domain=\"*\" to-ports=\"55555\"/> \n" +
"</cross-domain-policy>\u0000";
................
private void startListening()
{
provider = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
provider.Bind(new IPEndPoint(IPAddress.Parse("192.168.84.103"), PORT_NUMBER));
provider.Listen(10);
isListened = true;
while (isListened)
{
Socket socket = provider.Accept();
Console.WriteLine("connect!");
byte[] b = new byte[1024];
int receiveLength = 0;
try
{
// code jump out at this statement
receiveLength = socket.Receive(b);
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
String request = System.Text.Encoding.UTF8.GetString(b, 0, receiveLength);
Console.WriteLine("request:"+request);
if (request == POLICY_REQUEST)
{
socket.Send(Encoding.UTF8.GetBytes(POLICY_FILE));
Console.WriteLine("response:" + POLICY_FILE);
}
else if (request == END_REQUEST)
{
Dispose(socket);
}
else
{
StartSocket(socket); break;
}
}
}
Sorry for the long code, please someone help with it, thanks a million
that is because the socket policy file isn't requested on the port you are trying to join, but on the static port 843.
You should listen to port 843 to serve the policy requests. Also, I had some problems when immediately closing the socket after having sent the policy file. It seems that the socket should be left open for a few seconds after the policy file had been sent, otherwise Flash might simply drop the answer.
Note that this way, you can serve policy file requests from another application, not necessary from your main server.
The whole stuff is described in this documentation.
Related
I have an app on my android phone that sends a UDP packet with some information and I want to send this UDP packet to my Unity application. The android App works and sends the UDP packet (checked with wireshark) but somehow my C# script can't receive any. I googled and looked at similiar problems but none of them gave me an answer. I really don't know why it can't accept the packet.
I am broadcasting the UDP packet to make things easier but it doesn't seem to work. I also checked the ports.
Here is my C# code:
public class ControllerListener : MonoBehaviour
{
Thread receiveThread;
UdpClient client;
public int port;
public string lastReceivedUDPPacket = "";
public string allReceivedUDPPackets = "";
public void Start()
{
init();
}
// OnGUI
void OnGUI()
{
Rect rectObj = new Rect(40, 10, 200, 400);
GUIStyle style = new GUIStyle();
style.alignment = TextAnchor.UpperLeft;
GUI.Box(rectObj, "# UDPReceive\n127.0.0.1 " + port + " #\n"
+ "shell> nc -u 127.0.0.1 : " + port + " \n"
+ "\nLast Packet: \n" + lastReceivedUDPPacket
+ "\n\nAll Messages: \n" + allReceivedUDPPackets
, style);
}
public void Update()
{
}
// init
private void init()
{
print("UDPSend.init()");
// define port
port = 5678;
// status
print("Sending to 127.0.0.1 : " + port);
print("Test-Sending to this Port: nc -u 127.0.0.1 " + port + "");
receiveThread = new Thread(
new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Start();
}
// receive thread
private void ReceiveData()
{
client = new UdpClient(port);
while (true)
{
try
{
// Bytes empfangen.
IPEndPoint anyIP = new IPEndPoint(IPAddress.Broadcast, 5678);
byte[] data = client.Receive(ref anyIP);
// Bytes mit der UTF8-Kodierung in das Textformat kodieren.
string text = Encoding.UTF8.GetString(data);
// Den abgerufenen Text anzeigen.
print(">> " + text);
// latest UDPpacket
lastReceivedUDPPacket = text;
Thread.Sleep(8);
Debug.Log("Hier");
// ....
allReceivedUDPPackets = allReceivedUDPPackets + text;
}
catch (Exception err)
{
print(err.ToString());
}
}
}
// getLatestUDPPacket
// cleans up the rest
public string getLatestUDPPacket()
{
allReceivedUDPPackets = "";
return lastReceivedUDPPacket;
}
void OnDisable()
{
if (receiveThread != null)
receiveThread.Abort();
client.Close();
}
}
I just want to know why doesn't my code get out from the .Receive(...) method even though a UDP packet is broadcasted.
Thanks in advance (my first post on this site)
cheers
Udpclient.Receive will block until a datagram arrives from a remote host.
So if it doesn't return it simply means nothing was received yet.
This can have multiple reasons.
Afaik for IPEndPoint you should probably rather use
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
Which means the sender can have any IP address and send from any port. You limited the sender address to Broadcast which will probably never be the case since the sender can not have a broadcast adress. Also the senders outgoing port might not match 5678. 0 allows the sender to send from any port.
Sidenote: Thread.Sleep is in milliseconds so using only 8 also looks a bit odd ;)
I am working on a simple Client to send data to a server at my office. I tested the code locally on my computer using a server called TCPServer, I connect, send data, receive reply, disconnect, send again, rinse and repeat, it all works perfectly, but when I connect to office and do the same thing it connects fine, I can connect/disconnect forever, but when I send data it just hangs. Nothing is received in the log at the office. I can't send a single byte there.
Seems like a firewall issue doesn't it.
But I can run an older program I wrote years ago in Delphi (pascal), and it connects and sends the same data over without issue, same port, everything, so the problem is not a firewall issue. Thoughts on this? Here is the basic code layout.
Connect Button
Disconnect Button
Send Button
At the top of the class I declare the TcpClient Variable
public TcpClient m_client = new TcpClient();
In the _Click for Connect Button and Disconnect Button I have code to connect to server and set some indicators etc
private void ConnectButton_Click(object sender, EventArgs e)
{
string address = FixIP(IPAddressMaskedTextBox.Text);
int Port = Convert.ToInt32(PortNumberMaskedTextBox.Text);
Control control = (Control)sender;
String name = control.Name;
try
{
switch (name)
{
case ("ConnectButton"):
//Connect to server
connect(address, Port);
if (m_client.Connected)
{
SingleConnectionRichTextBox.Clear();
ConnectedLightButton.BackColor = Color.Lime;
SingleConnectionRichTextBox.Text += "Connected at IP " + address + " and Port " + Port.ToString() + "\r\n";
}
break;
case ("DisconnectButton"):
if (m_client.Connected)
{
SingleConnectionRichTextBox.Text += "Connection Terminated\r\n";
ConnectedLightButton.BackColor = Color.Red;
m_client.Client.Disconnect(false);
m_client = new TcpClient();
}
break;
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
public void connect(string address, int port)
{
try
{
if (!m_client.Connected)
{
ConnectedLightButton.BackColor = Color.Yellow;
SingleConnectionRichTextBox.Text += "Attempting to Connect...\r\n";
m_client.Connect(address, port);
}
else
{
SingleConnectionRichTextBox.Text += "Connection Failed...\r\n";
ConnectedLightButton.BackColor = Color.Red;
throw new Exception("Connect: Already connected\r\n");
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
The Send button has it's own event, mostly because when connecting to office it can take a minute for sockets to be created etc.
private void SendButton_Click(object sender, EventArgs e)
{
try
{
if (m_client.Connected)
{
string completeString = "";
for (int cnt = 0; cnt < SingleSendRichTextBox.Lines.Count() - 1; cnt++)
{
string aLine = Regex.Replace(SingleSendRichTextBox.Lines[cnt], #"\e\[(\d+;)*(\d+)?[ABCDHJKfmsu]", "");
if (cnt == 0)
{
//First line gets Start Block, plus a CR on end
aLine = (char)0x0B + aLine + (char)0x0D;
}
else if (cnt == (SingleSendRichTextBox.Lines.Count() -1))
{
//Last line gets CR + End Block + CR on end
aLine += (char)0x0D + (char)0x1C + (char)0x0D;
}
else
{
//All middle lines get CR on end
aLine += (char)0x0D;
}
//MessageBox.Show("Sending line# " + cnt.ToString() + " = " + aLine);
completeString += aLine;
}
Byte[] data = Encoding.ASCII.GetBytes(completeString);
WriteBytes(data);
ReadAllBytes();
}
else
{
MessageBox.Show("Nothing is connected currently...");
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
public void WriteBytes(Byte[] data)
{
try
{
if ((m_client.Connected)&&(data.Count() > 0))
{
// Get access to network stream
NetworkStream stm = m_client.GetStream();
stm.Write(data, 0, data.Length);
stm.Flush();
//MessageBox.Show("Data Sent, length = " + data.Length.ToString());
}
else
{
MessageBox.Show("Either we are not connected, or there is no data to send!!");
}
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
public void ReadAllBytes()
{
try
{
// Buffer to store the response bytes.
Byte[] readdata = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
NetworkStream stm = m_client.GetStream();
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stm.Read(readdata, 0, readdata.Length);
responseData = Encoding.ASCII.GetString(readdata, 0, bytes);
SingleReplyRichTextBox.Text += responseData + "\r\n";
}
catch (Exception err)
{
MessageBox.Show(err.ToString());
}
}
Does anything in here raise a red flag that is obvious? I tried Stream VS NetworkStream. I tried turning off the Reply listener. I took this code and combined it all into one function, and moved the TcpClient creation over to a different Class as static so I could create it in each function, but while all of these worked fine locally, nothing works connecting to office. It won't send a single byte. I set m_client as static at the top too, works fine locally, not to office.
Is GetStream failing maybe? or its sending the data on a different socket?
use a Task and cancellation token to cancel the task. Don't init a "new" TCPclient. In the background the TCPclient will be not closed (socket-timeout of .net)
Use try catches to see the exception and add the log to the conversation to make it more clear pls
I have written code for server and multiple client using threads and sockets. Normally the clients exits by sending the 'exit' keyword to server but I want the server to also detect situation when the clients exits forcefully without sending 'exit' keyword to server, for example when user in middle of sending message to server presses cross button of client window. What I want is that server should detect this situation and displays some error code and continue receiving message from other clients connected to it.
Second problem I am facing how can I disconnect server even if multiple clients are connected to it. In my code I am using tcpListener.Stop() but when i use this method error message "server failed to start at ipaddress" is displayed and number of such windows opens is equivalent to number of clients server is listening. For example if server is listening to 1000 clients then 1000 such windows will open showing the earlier mentioned error message which doesn't look good from the point of person using this software. So How can I handle this situation? Also in this situation if clients again starts sending message to the server then is also starts receiving messages even though I have disconnected the server. The server should remain disconnected until the user restarts server.
Following is my code for server.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
// Constants IP address of server and maximum number of clients server can connect.
static class Constants
{
public const string IP = "127.0.0.1";
public const int No_Of_Clients = 2;
}
// server port number
int port_number;
static IPAddress ipAddress = IPAddress.Parse(Constants.IP);
TcpListener tcpListener;
public Form1()
{
InitializeComponent();
button1.Click += button1_Click;
button2.Click += button2_Click;
//this.FormClosing += Form1_FormClosing;
}
//Socket socketForClient;
private void button1_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(textBox1.Text.Trim()))
{
System.Windows.Forms.MessageBox.Show("Port Number Empty", "Error");
}
else
{
port_number = int.Parse(textBox1.Text);
createserver(Constants.No_Of_Clients);
serveripaddress();
infoBox1.Text = string.Format("The server is now listening at port {0} at ip address {1}", port_number, Constants.IP);
infoBox1.Text = infoBox1.Text + "\r\n" + string.Format("The server can listen to maximum {0} number of clients", Constants.No_Of_Clients);
}
}
// this code disconnects the server
private void button2_Click(object sender, EventArgs e)
{
try
{
tcpListener.Stop();
}
catch (Exception f)
{
MessageBox.Show(f.Message);
}
}
public void serveripaddress()
{
serverip.Text = "Server IP : " + Constants.IP;
//serverport.Text = "Port Number : " + port.ToString();
}
// Starts server
private void createserver(int no_of_clients)
{
tcpListener = new TcpListener(ipAddress, port_number);
tcpListener.Start();
for (int i = 0; i < no_of_clients; i++)
{
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
}
} // end of createserver();
//listen to client receiving messages
public void Listeners()
{
Socket socketForClient;
try
{
socketForClient = tcpListener.AcceptSocket();
}
catch
{
System.Windows.Forms.MessageBox.Show(string.Format("Server failed to start at {0}:{1}", Constants.IP, port_number), "Error");
return;
}
if (socketForClient.Connected)
{
//System.Windows.Forms.MessageBox.Show("hello");
string string1 = string.Format("Client : " + socketForClient.RemoteEndPoint + " is now connected to server.");
infoBox1.Text = infoBox1.Text + "\r\n" + string1;
NetworkStream networkStream = new NetworkStream(socketForClient);
System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);
string theString = "";
while (true)
{
try
{
theString = streamReader.ReadLine();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
// if (streamReader.ReadLine() == null )
//{
// System.Windows.Forms.MessageBox.Show(string.Format("Server failed to start at {0}:{1}", Constants.IP, port_number), "Error");
// }
if (theString != "exit")
{
textBox2.Text = textBox2.Text + "\r\n" + "-----------------------------------------------------------------------------------";
string string2 = string.Format("Message recieved from client(" + socketForClient.RemoteEndPoint + ") : " + theString);
textBox2.Text = textBox2.Text + "\r\n" + string2;
// ASCII code for the message from client
string string3 = string.Format("ASCII Code for message is : ");
textBox2.Text = textBox2.Text + "\r\n" + string3;
string string4 = "";
foreach (char c in theString)
{
string4 += string.Format(System.Convert.ToInt32(c) + " ");
}
textBox2.Text = textBox2.Text + string4;
// Hex value of message from client
string hex = "";
foreach (char c in theString)
{
int tmp = c;
hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
}
string string5 = string.Format("Hex Code for the message from client : " + hex);
textBox2.Text = textBox2.Text + "\r\n" + string5;
//sending acknowledgement to client
try
{
socketForClient.Send(new ASCIIEncoding().GetBytes("The string was recieved from Client(" + socketForClient.RemoteEndPoint + ") : " + theString));
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
} // end of if loop
// if exit from client
else
{
string string7 = string.Format("Client " + socketForClient.RemoteEndPoint + " has exited");
infoBox1.Text = infoBox1.Text + "\r\n" + string7;
break;
}
} // end of while loop
streamReader.Close();
networkStream.Close();
streamWriter.Close();
} // end of if loop
socketForClient.Close();
}
}
}
To be informed about closed client connections you have to send periodically a 'heartbeat' message to the client. If the client connection died the tcp/ip mechanism will inform you after the timeout that the connection died (can't remember the name of the exception).
If the client wants to know if the connection died he has also to send a heartbeat message.
This is needed as the tcp connection recognizes lost connections only if data is sent over this connection.
For the second problem you should keep a list of all the active clients (your variable socketForClient). When you want to end your server you close all the client connections (the clients in the list).
I am making a chat service for a game,
I am using a TCP listener an client for the account information, some sort of login service. I'm wondering if i can keep the socked the client connected to the server with, to check if he is still online, and keep sending him messages if he has new messages.
I already tried making a list of sockets for the login queue, but it disconnected the previous socket to to server as soon as i accepted a new socket.
byte[] usernameByte = new byte[100];
int usernameRecieved = s.Receive(usernameByte);
//guiController.setText(System.DateTime.Now + " Recieved Login...");
byte[] passByte = new byte[100];
int passRecieved = s.Receive(passByte);
//guiController.setText(System.DateTime.Now + " Recieved Password...");
string username = "";
string password = "";
for (int i = 0; i < usernameRecieved; i++)
username += (Convert.ToChar(usernameByte[i]));
for (int i = 0; i < passRecieved; i++)
password += (Convert.ToChar(passByte[i]));
if (DomainController.getInstance().checkAccount(username, password))
{
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("true"));
s.Send(asen.GetBytes("U are succesfully logged in, press enter to continue"));
guiController.setText(serverName,System.DateTime.Now+"");
guiController.setText(serverName, "Sent Acknowledgement - Logged in");
}
else
{
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("false"));
s.Send(asen.GetBytes("U are NOT logged in, press enter to continue"));
guiController.setText(serverName, System.DateTime.Now + "");
guiController.setText(serverName, "\nSent Acknowledgement - Not logged in");
}
This is the code i currently use to check the account information the user send me. Right after i send this the user dropd the connection and i move on to the next one.
I have tried making 1 list of seperate sockets and processing them one by one, but that failed because the previous socket's connection dropped, even tho it were 2 different machines that tried to connect.
Does anyone have a sollution / a way to save sockets, that I can use to make the program keep all the connections alive? so i can send a message from user 1 to user 2, and just use the socket they connected with? or do i need to add an id every time they make a connection?
EDIT
The client Code: (this is just a test client)
while (true)
{
TcpClient tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
tcpclnt.Connect("xx.xxx.xxx.xx", 26862);
// use the ipaddress as in the server program
while(!(checkResponse(tcpclnt.GetStream())))
{
Thread.Sleep(1000);
}
Console.WriteLine("Connected");
Console.Write("Enter the string to be transmitted : ");
String str = Console.ReadLine();
if (str == "")
{
str = " ";
}
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
Console.WriteLine("Transmitting.....");
stm.Write(ba, 0, ba.Length);
Console.Write("Enter the string to be transmitted : ");
String str2 = Console.ReadLine();
if (str2 == "")
{
str2 = " ";
}
Stream stm2 = tcpclnt.GetStream();
ASCIIEncoding asen2 = new ASCIIEncoding();
byte[] ba2 = asen2.GetBytes(str2);
Console.WriteLine("Transmitting.....");
stm.Write(ba2, 0, ba2.Length);
if (str == "false")
{
blijvenWerken = false;
}
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
Console.Write(Convert.ToChar(bb[i]));
byte[] bb2 = new byte[100];
int k2 = stm.Read(bb2, 0, 100);
Console.Write("\n");
for (int i = 0; i < k2; i++)
Console.Write(Convert.ToChar(bb2[i]));
Console.WriteLine("\n");
tcpclnt.Close();
Thread.Sleep(1000);
}
Server getting the sockets:
This bit of code is on the loginserver, its because i can only accept 1 socket every time to keep the connection alive, that i put queueCount on a maximum of 1.
I want to be able to make a list of Sockets that i accepted to add to a User account.
while (loginServerOn)
{
if (queueCount < 1)
{
if (loginServer.getLoginListener().Pending())
{
loginQueue.Add(loginServer.getSocket());
ASCIIEncoding asen = new ASCIIEncoding();
Socket s = loginQueue.First();
try
{
s.Send(asen.GetBytes("true"));
queueCount++;
}
catch
{
loginQueue.Remove(s);
}
}
}
}
The function that returns the accepted socket.
public Socket getSocket()
{
return myList.AcceptSocket();
}
EDIT: Essence of the question
I want to add the socked or client recieved to my Account object, so every connection has an Account its linked to, when i want to send a message to a certain account, it should send a message to the socked or client bound to that account, can you help/show me how i can achieve this?
This is still c# and sockets but my approach is different to yours.
I went with the concept of a "connectedCleint" which is similar in purpose to what you've called an account.
I have a class called ServerTerminal which is responsible for accepting and top level management of socket connections. In this i've got:
public Dictionary<long, ConnectedClient> DictConnectedClients =
new Dictionary<long, ConnectedClient>();
So this is my list of connected clients indexed by the sockethandle.
To accept connections i've got a routine:
public void StartListen(int port)
{
socketClosed = false;
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//bind to local IP Address...
//if ip address is allready being used write to log
try
{
listenSocket.Bind(ipLocal);
}
catch (Exception excpt)
{
// Deal with this.. write your own log code here ?
socketClosed = true;
return;
}
//start listening...
listenSocket.Listen(100); // Max 100 connections for my app
// create the call back for any client connections...
listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);
}
So when a client connects it then fires off:
private void OnClientConnection(IAsyncResult asyn)
{
if (socketClosed)
{
return;
}
try
{
Socket clientSocket = listenSocket.EndAccept(asyn);
ConnectedClient connectedClient = new ConnectedClient(clientSocket, this, _ServerTerminalReceiveMode);
//connectedClient.MessageReceived += OnMessageReceived;
connectedClient.Disconnected += OnDisconnection;
connectedClient.dbMessageReceived += OndbMessageReceived;
connectedClient.ccSocketFaulted += ccSocketFaulted;
connectedClient.StartListening();
long key = clientSocket.Handle.ToInt64();
if (DictConnectedClients.ContainsKey(connectedClient.SocketHandleInt64))
{
// Already here - use your own error reporting..
}
lock (DictConnectedClients)
{
DictConnectedClients[key] = connectedClient;
}
// create the call back for any client connections...
listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);
}
catch (ObjectDisposedException excpt)
{
// Your own code here..
}
catch (Exception excpt)
{
// Your own code here...
}
}
The crucial part of this for you is:
// create the call back for any client connections...
listenSocket.BeginAccept(new AsyncCallback(OnClientConnection), null);
This sets up the serverterminal to receive new connections.
Edit:
Cut down version of my connectedclient:
public class ConnectedClient
{
private Socket mySocket;
private SocketIO mySocketIO;
private long _mySocketHandleInt64 = 0;
// These events are pass through; ConnectedClient offers them but really
// they are from SocketIO
public event TCPTerminal_ConnectDel Connected
{
add
{
mySocketIO.Connected += value;
}
remove
{
mySocketIO.Connected -= value;
}
}
public event TCPTerminal_DisconnectDel Disconnected
{
add
{
mySocketIO.Disconnected += value;
}
remove
{
mySocketIO.Disconnected -= value;
}
}
// Own Events
public event TCPTerminal_TxMessagePublished TxMessageReceived;
public delegate void SocketFaulted(ConnectedClient cc);
public event SocketFaulted ccSocketFaulted;
private void OnTxMessageReceived(Socket socket, TxMessage myTxMessage)
{
// process your message
}
private void OnMessageSent(int MessageNumber, int MessageType)
{
// successful send, do what you want..
}
public ConnectedClient(Socket clientSocket, ServerTerminal ParentST)
{
Init(clientSocket, ParentST, ReceiveMode.Handler);
}
public ConnectedClient(Socket clientSocket, ServerTerminal ParentST, ReceiveMode RecMode)
{
Init(clientSocket, ParentST, RecMode);
}
private void Init(Socket clientSocket, ServerTerminal ParentST, ReceiveMode RecMode)
{
ParentServerTerminal = ParentST;
_myReceiveMode = RecMode;
_FirstConnected = DateTime.Now;
mySocket = clientSocket;
_mySocketHandleInt64 = mySocket.Handle.ToInt64();
mySocketIO = new SocketIO(clientSocket, RecMode);
// Register for events
mySocketIO.TxMessageReceived += OnTxMessageReceived;
mySocketIO.MessageSent += OnMessageSent;
mySocketIO.dbMessageReceived += OndbMessageReceived;
}
public void StartListening()
{
mySocketIO.StartReceiving();
}
public void Close()
{
if (mySocketIO != null)
{
mySocketIO.Close();
mySocketIO = null;
}
try
{
mySocket.Close();
}
catch
{
// We're closing.. don't worry about it
}
}
public void SendMessage(int MessageNumber, int MessageType, string Message)
{
if (mySocket != null && mySocketIO != null)
{
try
{
mySocketIO.SendMessage(MessageNumber, MessageType, Message);
}
catch
{
// mySocketIO disposed inbetween check and call
}
}
else
{
// Raise socket faulted event
if (ccSocketFaulted != null)
ccSocketFaulted(this);
}
}
}
}
Some useful links:
This is where I started:
http://vadmyst.blogspot.com.au/2008/01/how-to-transfer-fixed-sized-data-with.html
http://vadmyst.blogspot.com.au/2008/03/part-2-how-to-transfer-fixed-sized-data.html
And..
C# Sockets and Multithreading
Cause a connected socket to accept new messages right after .BeginReceive?
http://nitoprograms.blogspot.com.au/2009/04/tcpip-net-sockets-faq.html
http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod
I can't post my entire solution just now; there is a flaw in my server code I need to debug; plus there are parts which my employer may not want published. But i based my code on what Vadym had for variable length messages.
When a server gets ready to accept TCP connections, it creates a new TCP socket, Bind() it to a port and uses the Listen() method. When a connection request comes in, the Listen() method returns a new socket that the server and client use for communication. The server and client can pass data back and forth using Send() and Receive() at this point. If the client disconnects, the server's Receive() terminates with 0 bytes of data.
If you want to wait for another connection request once you've accepted the first connection (i.e., while you are interacting with the first client) this can be done. At this point, you'll need to use something like threads or asynchronous methods so you can handle more than one connection. Basically, you will be able to Accept() connection requests from your listening socket.
Mike
I wrote a C# server application. The server utilizes Asynchronous TCP sockets.
The packets are 80-180 bytes of data.
For performance testing I have a single client connect and send packets continuously. With debugging on the first 100 packets (0-100) receive in roughly 5 seconds. By the time the server received packets #300-400 it takes roughly 30 seconds to receive the packets. The performance continues to degrade as more receives occur.
I looked around and have not been able to find a solution. I have tried setting the Socket.NoDelay flag in case the Nagle algorithm was inhibiting the server.
I have disabled all functions within the server; so that it is only receiving to ensure I wasn't losing performance in other code.
I have also checked my CPU utilization and it is ~13%. I have over 2 GB of free memory. When running the application the ram is NOT constantly growing and utilization is minimal.
I am at a loss as to what to debug and look into next...
EDIT: Added Code Sample
public void StartListening()
{
try
{
IPAddress ipAddress = IPAddress.Parse("192.168.2.60");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, m_Port);
m_MainSocket = new Socket(localEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
m_MainSocket.NoDelay = true;
m_MainSocket.Bind(localEndPoint);
m_MainSocket.Listen(10);
m_MainSocket.BeginAccept(new AsyncCallback(clientConnected), null);
System.Diagnostics.Debug.WriteLine("Listening on:Local IP Address: " + localEndPoint.Address.ToString() + " Port :" + localEndPoint.Port.ToString() + "\n");
}
catch (SocketException se)
{
System.Diagnostics.Debug.WriteLine("Listening Exception \n");
System.Diagnostics.Debug.WriteLine(se.Message);
}
}
void clientConnected(IAsyncResult ar)
{
try
{
SocketState state = new SocketState(m_MainSocket.EndAccept(ar));
Client client = new Client(state);
if (client.SocketState.clientSocket.Connected)
{
System.Diagnostics.Debug.WriteLine("Client #?????? Connected \n");
AddLogText("Client #?????? Connected \r\n\r\n");
waitForData(client);
SetSendButton(true);
}
m_MainSocket.BeginAccept(new AsyncCallback(clientConnected), null);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debug.WriteLine("Client Connected: Socket has been closed\n");
}
catch (SocketException se)
{
System.Diagnostics.Debug.WriteLine("Client Connected Exception \n");
System.Diagnostics.Debug.WriteLine(se.Message);
}
}
void waitForData(Client client)
{
try
{
SocketState state = new SocketState(client.SocketState.clientSocket);
client.SocketState.clientSocket = null;
client.SocketState = state;
client.SocketState.clientSocket.BeginReceive(client.SocketState.DataBuffer, 0, client.SocketState.DataBuffer.Length, SocketFlags.None, new AsyncCallback(readDataCallback), client);
}
catch (SocketException se)
{
System.Diagnostics.Debug.WriteLine("Wait For Data Exception \n");
System.Diagnostics.Debug.WriteLine(se.Message);
}
}
public void readDataCallback(IAsyncResult ar)
{
Client client = (Client)ar.AsyncState;
try
{
// Read data from the client socket.
int iRx = client.SocketState.clientSocket.EndReceive(ar);
client.SocketState.SB.Append(Encoding.ASCII.GetString(client.SocketState.DataBuffer, 0, iRx));
string sPacketString = client.SocketState.SB.ToString();
Server formServer = this;
Packet_Helper packet_helper = new Packet_Helper(sPacketString, formServer);
Packet packet = new Packet(sPacketString);
client.SerialNumber = packet.SerialNumber;
client.FirmwareVersion = packet.FirmwareVersion;
client.ProductID = packet.ProductID;
client.HardwareVersion = packet.HardwareVersion;
if (!m_Clients.ContainsKey(packet.SerialNumber))
{
m_Clients.Add(packet.SerialNumber, client);
UpdateClientList();
string[] packets = client.refreshAll();
for (int i = 0; i < packets.Length; i++)
{
byte[] byteData = Encoding.ASCII.GetBytes(packets[i]);
client.SocketState.clientSocket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
AddPacketsSentText(packets[i] + "--" + (iSent++).ToString() + "\r\n\r\n");
}
}
System.Diagnostics.Debug.WriteLine("Read " + sPacketString.Length.ToString() + " bytes from " + client.SerialNumber + "\n" + sPacketString + "\n");
AddLogText("Read " + sPacketString.Length.ToString() + " bytes from " + client.SerialNumber + " \r\n");
AddLogText(sPacketString.ToString() + "\r\n\r\n");
waitForData(client);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
if (se.ErrorCode == 10054) // Error code for Connection reset by peer
{
string sclientSerial = "??????";
if (client.SerialNumber != null || client.SerialNumber != "")
sclientSerial = client.SerialNumber;
AddLogText("Client " + sclientSerial + " Disconnected" + "\r\n\r\n");
System.Diagnostics.Debug.WriteLine("Client " + sclientSerial + " Disconnected" + "\n");
m_Clients.Remove(sclientSerial);
UpdateClientList();
}
else
{
System.Diagnostics.Debug.WriteLine("Read Data Exception \n");
System.Diagnostics.Debug.WriteLine(se.Message);
}
}
}
class SocketState
{
private Socket m_ClientSocket; //Socket connection to the client
private byte[] m_DataBuffer = new byte[256]; //Buffer to store the data sent by the client
private StringBuilder m_SB = new StringBuilder(); //for building recieved data into a string
/// <summary>
/// Gets or Sets the client Socket
/// </summary>
public Socket clientSocket
{
get { return m_ClientSocket; }
set { m_ClientSocket = value; }
}
/// <summary>
/// Gets the DataBuffer
/// </summary>
public byte[] DataBuffer
{
get { return m_DataBuffer; }
set { DataBuffer = value; }
}
/// <summary>
/// Gets or Sets the SB
/// </summary>
public StringBuilder SB
{
get { return m_SB; }
set { m_SB = value; }
}
public SocketState(Socket socket)
{
m_ClientSocket = socket;
m_ClientSocket.ReceiveBufferSize = 256;
m_ClientSocket.NoDelay = true;
//m_DataBuffer = Enumerable.Repeat((byte)0, 256).ToArray();
}
}
Edit: AddLogText() function added. This function is used to add text to a Text Box that is in the UI.
//Delegate - enables asychronous calls for setting the text property of the tb_ListeningLog
delegate void AddLogTextCallback(string text);
private void AddLogText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.tb_ListeningLog.InvokeRequired)
{
AddLogTextCallback d = new AddLogTextCallback(AddLogText);
this.Invoke(d, new object[] { text });
}
else
{
this.tb_ListeningLog.Text += text;
tb_ListeningLog.SelectionStart = tb_ListeningLog.Text.Length;
tb_ListeningLog.ScrollToCaret();
}
}
I'm taking a bit of a shot in the dark with this answer, but the code you've posted certainly helps.
The reason you're probably seeing slow performance as time goes on is because of the code in your readDataCallback method. The way you have it set up, the processing of the data is done before you go for another receive. This means that as the length of the processing increases, the duration between receiving your data increases.
I don't know what code is in a lot of your methods, but you should generally look at any loops that may be taking a while to finish. If you're having trouble finding the bottleneck by looking through your code, try finding which methods take the longest to finish and continue to narrow your code down.
For instance (I'm guessing that the bottleneck is in this area of code):
if (!m_Clients.ContainsKey(packet.SerialNumber))
{
m_Clients.Add(packet.SerialNumber, client);
AddLogText("Running UpdateClientList\r\n");
UpdateClientList();
AddLogText("Doing client.refreshAll\r\n");
string[] packets = client.refreshAll();
AddLogText("Doing for loop\r\n");
for (int i = 0; i < packets.Length; i++)
{
byte[] byteData = Encoding.ASCII.GetBytes(packets[i]);
client.SocketState.clientSocket.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
AddPacketsSentText(packets[i] + "--" + (iSent++).ToString() + "\r\n\r\n");
}
}
Just observe the amount of time between each method with your eyes, or make it easier and use a Stopwatch or DateTime to show exact time.
Also, if you find that the behavior of the code cannot be made more efficient, you could toy around with the idea of processing the data in a separate thread. I'm assuming that this behavior isn't desired, though, because of the question at hand.
For your AddLogText method, try using tb_ListeningLog.Text.AppendText instead of +=.
I am not sure why you have such a long piece of code to read more data. Also, try placing the message in a Queue which can be processed by a different thread.
Here is an implementation I use:
// Read data from the client
private void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.workSocket;
try
{
if (socket.Connected)
{
// Read the socket
int bytesRead = socket.EndReceive(ar);
// Deserialize objects
foreach (MessageBase msg in MessageBase.Receive(socket, bytesRead, state))
{
// Add objects to the message queue
lock (this.messageQueue)
messageQueue.Enqueue(msg);
}
// Notify any event handlers
if (DataRecieved != null)
DataRecieved(socket, bytesRead);
// Asynchronously read more client data
socket.BeginReceive(state.Buffer, state.readOffset, state.BufferSize - state.readOffset, 0,
ReadCallback, state);
}
else
{
HandleClientDisconnect(socket);
}
}
catch (SocketException)
{
HandleClientDisconnect(socket);
}
}