Subscriber/receive data from publisher using nanomsg. - c#

I'm using the C# data binding for nanomsg. I have an external program that is sending Google Protocol Buffer messages on the url ipc://report_data and my subscriber connects to that same exact url. So, I would expect my subscriber to be able to retrieve any data being sent on that url, however, it is not. I use the function Receive() and nothing ever comes through. There is only one type of message coming through on that URL so I'm not concerned about the topic. Does anyone with experience with nanomsg know how to read ANY data that comes in on the transport url, regardless of topic?
This is the code for my subscriber and receiving messages:
public static void CreateSubscriber(string url, string topic)
{
Console.WriteLine("\nCreating new subscriber with topic {0} and url {1}.", topic, url);
var subscriber = new SubscribeSocket();
subscriber.Connect(url);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 5000)
{
if (sw.Elapsed.TotalSeconds % 3 == 0)
{
Console.WriteLine("Checking for new data.");
var streamOutput = ReceiveProtoBufferMessage(subscriber, topic);
}
}
sw.Stop();
Thread.Sleep(1);
Console.WriteLine("Disposing subscriber.");
subscriber.Dispose();
}
static byte[] ReceiveProtoBufferMessage(SubscribeSocket s, string topic)
{
byte[] data = null;
try
{
data = s.Receive();
Console.WriteLine("Received data.");
}
catch
{
Console.WriteLine("Couldn't receive data.");
}
if (data != null)
{
Console.WriteLine("Data is not null.");
}
else
{
Console.WriteLine("Null data");
}
return data;
}

Figured it out - in order to make the subscriber pick up all messages I made the subscriber subscribe to an empty string topic: "".

Related

TCP Receive does not return expected number of bytes

I using TCPIP to get data from a controller. When using TCPIP to receive data, i only can get the first line on data which mean the data length is 1514, but the another line of data which is length 174 are unable to get from TCPIP Client protocol at C#. May need you guys to advise on this.
Picture Below is used Wireshark to trace the TCPIP data.
Below picture is the method used to receive data from TCPIP Client Protocol.
Thanks.
Here is how I approach to connect and get data from TCPIP. Please correct me if that was a mistake.
public void Connect(string ipAddress, int port)
{
lock (this)
{
try
{
IPAdddress = ipAddress;
Port = port;
IPAddress ip = IPAddress.Parse(ipAddress);
IPEndPoint endPoint = new IPEndPoint(ip, port);
Client.BeginConnect(endPoint, new AsyncCallback(OnClientConnected), null);
}
catch (Exception ex)
{
ExceptionThrownEventArgs args = new ExceptionThrownEventArgs();
args.Exception = ex;
if (m_ExceptionThrown != null)
{
foreach (Delegate del in m_ExceptionThrown.GetInvocationList())
{
ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
if (syncer == null)
{
del.DynamicInvoke(this, args);
}
else
{
syncer.BeginInvoke(del, new object[] { this, args });
}
}
#endregion
}
// SupportMethod.ShowExceptionMessage(ex, Output.EventLog);
}
}
}
private void OnMessageReceived(IAsyncResult result)
{
try
{
Metadata metadata = (Metadata)result.AsyncState;
if (metadata.ReceiveBuf[0] == 0)
{
Disconnect();
}
else
{
Client.EndReceive(result);
var e = Encoding.GetEncoding("iso-8859-1");
LastMessageReceived = e.GetString(metadata.ReceiveBuf).Trim('\0');
Debug.Print("TCPRaw: " + LastMessageReceived);
if (m_EchoOnReceived)
{
Echo(LastMessageReceived);
}
MessageReceivedEventArgs args = new MessageReceivedEventArgs();
if (m_MessageReceived != null)
{
#region Fire the MessageReceived event (bound during instantiation of ClientSocket).
foreach (Delegate del in m_MessageReceived.GetInvocationList())
{
ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
if (syncer == null)
{
del.DynamicInvoke(this, args);
}
else
{
syncer.BeginInvoke(del, new object[] { this, args });
}
}
#endregion
}
// Provide additional data for the socket operation. Re-instantiate a new Metadata object.
metadata = new Metadata();
metadata.ReceiveBuf = new byte[m_ReceiveBufSize];
// Continue to prepare receive data from the connected Server.
Client.BeginReceive(
metadata.ReceiveBuf,
0,
metadata.ReceiveBuf.Length,
SocketFlags.None,
new AsyncCallback(OnMessageReceived),
metadata);
}
}
catch (Exception ex)
{
ExceptionThrownEventArgs args = new ExceptionThrownEventArgs();
args.Exception = ex;
// ExceptionThrown Event.
if (m_ExceptionThrown != null)
{
#region Fire the ExceptionThrown event (bound during instantiation of ClientSocket).
// Check the Target of each delegate in the event's invocation list, and marshal the call
// to the target thread if that target is ISynchronizeInvoke
// ref: http://stackoverflow.com/questions/1698889/raise-events-in-net-on-the-main-ui-thread
foreach (Delegate del in m_ExceptionThrown.GetInvocationList())
{
ISynchronizeInvoke syncer = del.Target as ISynchronizeInvoke;
if (syncer == null)
{
del.DynamicInvoke(this, args);
}
else
{
syncer.BeginInvoke(del, new object[] { this, args });
}
}
#endregion
}
// SupportMethod.ShowExceptionMessage(ex, Output.EventLog);
}
}
For TCP/IP, when you specify the number of bytes to receive in a Receive method, it is an upper limit, not an absolute number of bytes. If you receive less than the requested number of bytes, you need to do another read and combine the results together into the data you want. This is why the Receive method allows you to specify the index into the array to put the received data. For example:
var message = new byte[myMessageSize];
var totalBytesReceived = 0;
while (totalBytesReceived < myMessageSize)
{
var bytesReceived = socket.Receive(message,
totalBytesReceived,
myMessageSize - totalBytesReceived,
SocketFlags.None);
totalBytesReceived += bytesReceived;
}
I recommend against using BeginReceive, the callbacks are difficult to manage and most people do it wrong. Use the synchronous methods or ReceiveAsync().

Possible data loss on TcpClient?

I'm writing some code for a production line. In particular I need to integrate some barcode reader into the line.
For many (wrong) reason I had to end up like you are about to see.
Also, I was new to that field at the time I wrote that.
The issue: Sometimes, the reader reads the code (and send the image via ftp) but I get no data in my software and I need to understand why.
This is how initialize my reader (I have multiple reader, each with different IP but same port)
server = new TcpListener(IPAddress.Any, scannerPort);
server.Start();
Thread thread = new Thread(() =>
{
log.Debug("Waiting for scanner connection");
server.BeginAcceptTcpClient(HandleAsyncConnection, server);
});
thread.Start();
and this is my main method:
try
{
object _lockObj = new object();
using (TcpClient client = server.EndAcceptTcpClient(res))
{
int i;
server.BeginAcceptTcpClient(HandleAsyncConnection, server);
string address = client.Client.RemoteEndPoint.ToString();
string senderIp = address.Split(':')[0];
NetworkStream stream = client.GetStream();
Byte[] bytes = new Byte[2048];
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
log.Debug("Start");
lock (_lockObj)
{
log.Debug("Lock");
StringBuilder sb = new StringBuilder(string.Empty);
string rawCode = string.Empty;
bool isCrFound = false;
foreach (byte c in bytes.Where(x => x != 0))
{
if (c != (char)13 && !isCrFound)
{
if (c == (char)29)
{
sb.Append("<GS>");
}
else
sb.Append(Convert.ToChar(c));
}
else
{
isCrFound = true;
}
}
rawCode = sb.ToString();
log.Debug("Raw code from {0} -> {1}", senderIp, rawCode);
if (rawCode.StartsWith("ERROR", StringComparison.InvariantCultureIgnoreCase))
{
log.Debug("Operator - Errore reading code {0} from {1}", rawCode, senderIp);
}
else
{
//Process code
}
log.Debug("End");
}
log.Debug("Unlock");
}
}
}
catch (Exception ex)
{
log.Error("Error on the async connect operation: {0}, Stack: {1}", ex.Message, ex.StackTrace);
}
So basically everytime a sensor trigger, data is sent to my socket.
This works pretty well until the line starts to speed up (like 3/4 code/second); that is when data loss happen.
Now, I don't know where the issue is. Could be the devide, my implementation, resources management (byte array was 1024, I still have to try the 2048)
Any help would be much appreciated.
Thanks
EDIT:
I already stripped some log for brevity
I need a lock because when a sensor triggers too close to another, messages got overlapped (to that add different business reason)
When I loose Codes, I don't have anything in my log; the log, usually looks like:
start
Lock
lot of stuff
end
unlock
Lost codes don't leave any trace on my log... so I don't think it's something related to data discarded.
What I'd like to know if there is a way to do this kind of thing better in a context like mine.

Azure: How to Delete "DeadLettered" Messages from Service Bus queue

I would like to delete the Dead Lettered messages from the service bus queue. In particular, this value is called DeadLetterMessageCount and you can find out this by right-clicking the "Properties" of the SB queue in the Server Explorer of your project (in case of using a SB queue).
The reason I would like to do this is because I've set up an Autoscale of the cloud service. So, when the SB queue is quite big, it adds some more cores in order to proceed the messages faster (it enables more worker roles). I realized that when you set up the scaling depending on the number of messages in the queue, it counts the DeadLettered messages as well (messages that cannot be consumed).
So that's a waste of money, as more instances are enabled that are not needed.
Any queries, please let me know.
Thanks for your help
You read and delete messages from dead letter queue the same way you read from normal queues or subscriptions.
You can use this method to get the path of the queue: QueueClient.FormatDeadLetterPath(queuePath).
Also see this previous answer: How do I delete a DeadLetter message on an Azure Service Bus Topic
This is a code to delete a Dead-Letter messages from Queues.
public async void DeleteMessagesFromQueueAsync()
{
bool isDeadLetter=true;
long SequenceNumber = 12;
string queuePath='queue name';
string connectionString='connection string of ASB Namespace';
BrokeredMessage _srcMessage = null;
DeleteMessageResponse _msgDeletionStatus = new DeleteMessageResponse();
MessageReceiver fromQueueClient = null;
try
{
MessagingFactory factory = MessagingFactory.CreateFromConnectionString(connectionString);
string _fromEntityPath = !isDeadLetter ? queuePath : QueueClient.FormatDeadLetterPath(queuePath);
fromQueueClient = await factory.CreateMessageReceiverAsync(_fromEntityPath, ReceiveMode.PeekLock);
BrokeredMessage _message = await fromQueueClient.ReceiveAsync(SequenceNumber);
if (_message != null)
_srcMessage= _message;
if (_srcMessage != null )
{
await _srcMessage.CompleteAsync();
}
}
catch (Exception ex)
{
}
finally
{
if (fromQueueClient != null)
await fromQueueClient.CloseAsync();
}
}
You can use 'ReceiveAndDelete' mode and 'ReceiveBatchAsync' to delete quickly from DeadLetterQueue
private async void button1_Click(object sender, EventArgs e)
{
try
{
var DLQPath = "/$DeadLetterQueue"; ///**** Important - Pointing to DLQ'
var topicName = "message";
var sub = "message-subscription";
int batchSize = 100;
runProcess = true;
_subscriptionClient = SubscriptionClient.CreateFromConnectionString(connectionSt, topicName, sub + DLQPath, ReceiveMode.ReceiveAndDelete);
int cnt = 0;
do
{
var messages = await _subscriptionClient.ReceiveBatchAsync(batchSize);
var msgCount = messages.Count();
if (msgCount == 0)
{
break;
}
cnt += msgCount;
labelCount.Text = cnt.ToString();
}
while (runProcess);
_subscriptionClient.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.GetBaseException().Message);
return;
}
}

Identify an incoming file through NetworkStream C#

I am making a client/server chat application using TcpClient and TcpListener classes. It should be able to transfer text messages and files between client and server. I am able to handle text messages by making a thread for each separate client and then making a secondary thread for receiving incoming message making primary thread reserved for sending messages. Now if I would be able to identify that incoming message is a file and not a text message then I know how to handle it using NetworkStream and FileStream. But I am unable to do so. Code to handle incoming file is here. Also please tell me if there are any limitations using NetworkStream for FTP.
Answer: Build your own protocol.
By building your own good communication protocol you can control all data/message flow.
For example;
1-User wants to send a file to server
2-Client sends a command to inform the server that it will send a file.Like ;
#File#filename;filesize;
3-Server sends a ready message back to client #FileAccepted#
4-Server begins to listen buffer packages and when it receives writes them to an stream.
5-When client receives {#FileAccepted#} command begins to send packages to server. Be sure their buffer sizes are same.
6-When all bytes complete client sends #FileEnd# in diffrent buffer (i use 256 for commands and 1024 for file transfer)
7-When server receives 256 byte command looks if its the #FileEnd# command and is true flushes file stream and closes connection.
I recomment you use Async
Listen for connections on server like this
server.BeginAcceptTcpClient(ServerAcceptEnd,server);
And when a connection is present
public void ServerAcceptEnd(IAsyncResult ar)
{
if(!ar.IsCompleted)
{
//Something went wrong
AcceptServer();
return;
}
try
{
var cli = servertc.EndAcceptTcpClient(ar);
if(cli.Connected)
{
//Get the first Command
cli.GetStream().BeginRead(serverredbuffer,0,serverredbuffer.Length,ServerFirstReadEnd,cli);
}
else
{
//Connection was not successfull log and wait
AcceptServer();
}
}
catch(Exceiption ex)
{
//An error occur log and wait for new connections
AcceptServer();
}
}
When first command received ;
public void ServerFirstReadEnd(IAsyncResult ar)
{
if(!ar.IsCompleted)
{
//Something went wrong
AcceptServer();
return;
}
try
{
TcpClient cli = (TcpClient)ar.AsyncState;
int read = cli.GetStream().EndRead(ar);
string req = toString(serverredbuffer);
if(req.StartsWith("#File#"))
{
//File Received
string filename = req.Replace("#File#","");
string[] spp = filename.Split(';');
filename = spp[0];
serverreceivetotalbytes = Convert.ToInt64(spp[1]);
cli.GetStream().Write(toByte("#FileAccepted#",256),0,256);
cli.GetStream().BeginRead(serverreceivebuffer,0,1024,ServerReadFileCyle,cli)
}
else
{
//Message Received
}
}
catch(Exception ex)
{
//An error occur log and wait for new connections
AcceptServer();
}
}
File receive method ;
public void ServerReadFileCyle(IAsyncResult ar)
{
TcpClient cli = (TcpClient)ar.AsyncState;
if(ar.IsCompleted)
{
int read = cli.GetStream().EndRead(ar);
if(read == 256)
{
try
{
string res = toString(serverreceivebuffer);
if(res == "#FileEnd#")
read = 0;
}
catch
{
}
}
if(read > 0)
{
serverfile.Write(serverreceivebuffer,0,read);
cli.GetStream().BeginRead(serverreceivebuffer,0,1024,ServerReadFileCyle,cli);
}
else
{
serverfile.Flush();
serverfile.Dispose();
AcceptServer();
}
}
}
This part was server side.And for client side;
When sending a file first send a information to server for file and then wait for a response from server.
try
{
System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
ofd.Multiselect = false;
ofd.FileName="";
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
filesendpath = ofd.FileName;
senderfilestream = System.IO.File.Open(filesendpath,System.IO.FileMode.Open);
sendertotalbytes = senderfilestream.Length;
filesendcommand = "#File#" + System.IO.Path.GetFileName(filesendpath) + ";" + senderfilestream.Length;
senderfilestream.Position = 0;
sendertc.BeginConnect(ip.Address,55502,FileConnect,null);
}
else
{
//No file selected
}
}
catch(Exception ex)
{
//Error connecting log the error
}
If connection is successfull , then send the file command and wait for response ;
public void FileConnect(IAsyncResult ar)
{
if(ar.IsCompleted)
{
sender.EndConnect(ar);
if(sender.Connected)
{
sender.GetStream().Write(toByte(filesendcommand,256),0,256);
sender.GetStream().BeginRead(ComputerNameBuffer,0,256,FileSendCyleStarter,null);
}
}
}
When response received look if it is successfull an accepted;
public void FileSendCyleStarter(IAsyncResult ar)
{
if(ar.IsCompleted)
{
if(sender.Connected)
{
string kabul = toString(ComputerNameBuffer);
if(kabul == "#FileAccepted#")
{
senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null);
}
}
}
}
Sending a file has three steps;
1-Read a chunk for a start
2-Then send the chunk to server.if its completed send #FileEnd# command and skip step 3
3-Read next chunk of file
4-Return step 2 if file isnt completed
Step 1 :
senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null);
Step 2-4 :
public void FileSendCyle(IAsyncResult ar)
{
if(ar.IsCompleted)
{
if(sendertc.Connected)
{
int read = senderfilestream.EndRead(ar);
if(read > 0)
{
sendertc.GetStream().BeginWrite(filesendbuffer,0,read,FileSendCyle2,null);
}
else
{
sendertc.GetStream().Write(toByte("#FileEnd#",256),0,256);
}
}
}
}
Step 3 :
public void FileSendCyle2(IAsyncResult ar)
{
if(ar.IsCompleted)
{
if(sendertc.Connected)
{
sendertc.GetStream().EndWrite(ar);
senderfilestream.BeginRead(filesendbuffer,0,1024,FileSendCyle,null);
}
}
}
In abowe example there are two methods called toString() and toByte().I used them for converting strings to bytes and bytes to strings.Here are them ;
public string toString(byte[] buffer)
{
return Encoding.UTF8.GetString(buffer).Replace("\0","");
}
public byte[] toByte(string str,int bufferlenght)
{
byte[] buffer = new byte[256];
Encoding.UTF8.GetBytes(str,0,str.Length,buffer,0);
return buffer;
}
The code abowe example isn't perfect and need lots of error handling and flow controls.I write theese to give you an idea and a jump start.
Hope any part of it helps anybody ^_^

Chat service application

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

Categories