Transferring multiple commands/decisions through tcp socket - c#

Good afternoon all!
The goal of the project:
Build a notification program with client, console, and server executable. Only selected users should get the notification.
The problem:
Sometimes the code works great, and everything works (20% of runs). The rest of the time, it will mess up the order the data is being sent in.
The code:
Server (console = TCPclient):
private void Connect()
{
string username = ReadFromConsole();
if (IsUserAllowed(username)) // Receive username
SendToConsole(bool.TrueString); // Send confirmation
else
{
SendToConsole(bool.FalseString); // Send denial
console.Close();
return;
}
string messageID = ReadFromConsole(); // Receive MessageID
string recipientCount = ReadFromConsole();
int numOfRecipients = int.Parse(recipientCount); // Receive and parse number of recipients
List<string> recipients = new List<string>();
for (int i = 0; i < numOfRecipients; i++)
{
string recipient = ReadFromConsole();
recipients.Add(recipient); // Receive recipient, add to list (required for Message)
}
string department = ReadFromConsole(); // Receive department string
string visibleTime = ReadFromConsole(); // Receive visibility timespan
string expiration = ReadFromConsole(); // Receive expiration datetime
StoreRTF(messageID); // Receive and store RTF file
console.Close(); // Connection is done, close
Message message = new Message(messageID, department, recipients, visibleTime, expiration);
}
Console (server = TCPclient):
private void SendMessage()
{
SendToServer(Environment.UserName);
if (bool.Parse(ReadFromServer()))
{
// User is allowed, continue
string messageID = DateTime.Now.ToUniversalTime().Ticks.ToString();
SendToServer(messageID); // MessageID
string recipientCount = lvRecipients.Items.Count.ToString();
SendToServer(lvRecipients.Items.Count.ToString()); // Amount of recipients
foreach (string item in lvRecipients.Items) // Loop to send each recipient
{
SendToServer(item);
}
string department = TB_Department.Text;
SendToServer(department); // Send department string
string visibleTime = TimeSpan.FromSeconds(SLIDER_VisibleTime.Value).Ticks.ToString();
SendToServer(visibleTime); // Send message visibility time
string expiration = DateTime.Now.ToUniversalTime().AddMinutes(2).ToString();
SendToServer(expiration); //TODO add UI control for this
SendRTFToServer(); // Send RTF file
MessageBox.Show(
"Your designated MessageID is: " + messageID + Environment.NewLine +
"Message upload is succesful.",
"Complete",
MessageBoxButton.OK);
}
else
{
// User is not allowed. Report to user. Disconnect (will be managed by the finally block)
MessageBox.Show("You are not allowed to upload messages to the server.", "Access denied", MessageBoxButton.OK, MessageBoxImage.Stop);
return;
}
}
Send and receive parts (same between console/server/client):
private void SendToServer(string toSend)
{
while (server.GetStream().DataAvailable)
{
// Should wait
}
StreamWriter writer = new StreamWriter(server.GetStream());
writer.WriteLine(toSend);
writer.Flush();
}
private void SendRTFToServer()
{
while (server.GetStream().DataAvailable)
{
// Should wait
}
File.Open(RTFLocation, FileMode.Open, FileAccess.Read).CopyTo(server.GetStream());
server.GetStream().Flush();
server.GetStream().Close();
}
private string ReadFromServer()
{
server.GetStream().Flush();
StreamReader reader = new StreamReader(server.GetStream());
return reader.ReadLine();
}
I have also tried different loops, implementations, switching to byte[]...
After lots of debugging I am getting nowhere. I have checked which information is leaving the console, and that all checks out and is in the right order. However, at the server end it seems to be receiving it in an entirely different order.
Anyone have an idea what is causing this?

I've found how to properly handle this. Code for the relevant parts can be found here:
C# Sockets send/receive problems and questions
Hope this may help someone in the future!

Related

How Get data Trough DNS in C# Unity3D

I have a database that stores players stats. The database isn't working with my IP, so I want to get the data from a DNS (like 1.1.1.1)
How can I make C# script to go through the DNS?
The Problem is this Azuara blocks Iranian IP and i want somehow Get a Work Around it
enter image description here
This is my C# code in Unity:
public void GetUserData(OnDataReceivedCallback onDataReceived)
{ //called when the 'Get Data' button on the data part is pressed
if (IsLoggedIn)
{
//ready to send request
StartCoroutine(sendGetDataRequest(LoggedIn_Username, LoggedIn_Password, onDataReceived)); //calls function to send get data request
}
}
IEnumerator sendGetDataRequest(string username, string password, OnDataReceivedCallback onDataReceived)
{
string data = "ERROR";
IEnumerator e = DCF.GetUserData(LoggedIn_Username, LoggedIn_Password); // << Send request to get the player's data string. Provides the username and password
while (e.MoveNext())
{
yield return e.Current;
}
string response = e.Current as string; // << The returned string from the request
if (response == "Error")
{
//There was another error. Automatically logs player out. This error message should never appear, but is here just in case.
LoggedIn_Username = "";
LoggedIn_Password = "";
Debug.Log("Error: Unknown Error. Please try again later.");
}
else
{
data = response;
}
if (onDataReceived != null)
onDataReceived.Invoke(data);
}

Trigger notification once in a loop

I have a loop that is running every 10 seconds that does a few things. One thing it does is it enables a button when there is a message that I am sending to the users of the app. I want to send a notification to the system tray when that button enables, but for obvious reasons I only want that notification triggered once when the user has an unread broadcast.
Here is the code I have:
private void EnableBroadcasts()
{
string query = "SELECT COUNT(*) FROM db.broadcasts WHERE broadcast_active = '1'";
int count = StoredProcedures.CountRecordsT4(query);
StreamReader re = new StreamReader(#"C:\\Users\\" + Environment.UserName + #"\\appdata\\Local\\Cache\\broadcasts.cache");
List<string> ReadBroadcastList = new List<string>();
List<string> BcastID = BroadcastID();
if (BroadcastCount != count)
{
string text = re.ReadToEnd();
re.Close();
string[] lines = text.Split('\r');
foreach (string s in lines)
{
ReadBroadcastList.Add(s);
}
for (int t = 0; t < ReadBroadcastList.Count(); t++)
{
ReadBroadcastList[t] = ReadBroadcastList[t].Trim('\n');
}
ReadBroadcastList.Remove("");
BroadcastCount = ReadBroadcastList.Count();
}
var test = BcastID.Except(ReadBroadcastList).ToList();
int read = test.Count();
if (count != 0)
{
btnWESBroadcast.Visible = true;
}
else
{
btnWESBroadcast.Visible = false;
}
The button enables once count is not zero. I have a list of broadcast ID's that are active from the db,I also have a cache file that records what broadcast ID's that user has read.
I am looking for a solution that will have the notification only run when the button is active and there is a broadcast that the user has not read.
Wrap your string broadcast in a simple type: BroadcastMessage. Add a bool IsRead flag.
Mark IsRead = true and the message will be ignored with the following logic.
// pseudo
if (button.IsEnabled && ReadBroadcastList.Any(msg => !msg.IsRead)) {
NotifyTray();
}
Then you can later add a feature for the user to mark a message Unread.
If you intend to persist this data in the database, then both the message and flag can be stored in the BroadcastMessage object. When a user reads the message and the object is marked as read, update the database with the change.
Update: based on clarification in comment
Add a bool IsNotified flag to the BroadcastMessage notification and check !msg.IsNotified instead of !msg.IsRead.

Simple Chat Client-Server Encryption

I wanted to make a chat client server, very simple, but at the same time very safe, using AES-256bit. I have thought so, tell me if I'm wrong, of course.
The various client enter in a "secure" textbox the passwords (which must be the same everywhere) and in the sending functions (of the client program), clients encrypt messages that I put in another ordinary textbox, using the password and send them to the server; the receiving function always decrypts always using the same key. The server should instead do nothing at the encryption level.
I tried, but I do not know if it doesn't work because of at the code level.
Here's how I modified both the sending and receiving functions on the client: send function
// send the message to the server
private void SendMessage()
{
if (txtMessage.Lines.Length >= 1)
{
byte[] passwordBytes = GetPasswordBytes();
encrypted_message = AES.Encrypt(txtMessage.Text, passwordBytes);
swSender.WriteLine(encrypted_message);
swSender.Flush();
txtMessage.Lines = null;
}
txtMessage.Text = "";
}
receiving function:
private void ReceiveMessages()
{
// Receive the response from the server
srReceiver = new StreamReader(tcpServer.GetStream());
// If the first character of the response is 1, connection was successful
string ConResponse = srReceiver.ReadLine();
// If the first character is a 1, connection was successful
if (ConResponse[0] == '1')
{
// Update the form to tell it we are now connected
this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Connessione avvenuta con successo!" });
}
else // If the first character is not a 1 (probably a 0), the connection was unsuccessful
{
string Reason = "Non connesso: ";
// Extract the reason out of the response message. The reason starts at the 3rd character
Reason += ConResponse.Substring(2, ConResponse.Length - 2);
// Update the form with the reason why we couldn't connect
this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
// Exit the method
return;
}
// While we are successfully connected, read incoming lines from the server
while (Connected == true)
{
try
{
// Show the messages decrypted in the log TextBox
this.Invoke(new UpdateLogCallback(this.MessageUpdateLog), new object[] { srReceiver.ReadLine() });
}
catch
{
try
{
this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
}
catch { }
}
}
}
// This method is called from a different thread in order to update the log TextBox
private void UpdateLog(string strMessage)
{
txtLog.AppendText(strMessage + "\r\n");
}
//Decrypt the messages incoming from the other client
private void MessageUpdateLog(string strMessage_de)
{
byte[] passwordBytes = GetPasswordBytes();
strMessage_de = AES.Decrypt(strMessage_de, passwordBytes);
// Append text also scrolls the TextBox to the bottom each time
txtLog.AppendText(strMessage_de + "\r\n");
}
not to make the job hard, I thought of exchange encryption passwords (keys) via voice, since it would be a chat room for personal use.

blocking listen prevents disconnect

Overview of Problem:
I need to connect to an IRC Server. Once connected, the program will send a message to the channel, and a response will occur over multiple lines back. I need to read these lines and store in a variable for later use. A special character at the end of the message (]) will define the end of the message over multiple lines. Once we have received this character, the IRC session should disconnect and processing should continue.
Situation:
I am using the Smartirc4net library. Calling irc.Disconnect() takes about 40 seconds to disconnect the session. Once we've received the ] character, the session should be disconnected, Listen() should not be blocking, and the rest of the program should continue to run.
Research:
I have found this: smartirc4net listens forever, can't exit thread, and I think it might be the same issue, however, I am unsure of what I need to do to resolve the problem.
Code:
public class IrcCommunicator
{
public IrcClient irc = new IrcClient();
string data;
public string Data { get { return data; } }
// this method we will use to analyse queries (also known as private messages)
public void OnQueryMessage(object sender, IrcEventArgs e)
{
data += e.Data.Message;
if (e.Data.Message.Contains("]"))
{
irc.Disconnect(); //THIS TAKES 40 SECONDS!!!
}
}
public void RunCommand()
{
irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
string[] serverlist;
serverlist = new string[] { "127.0.0.1" };
int port = 6667;
string channel = "#test";
try
{
irc.Connect(serverlist, port);
}
catch (ConnectionException e)
{
// something went wrong, the reason will be shown
System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
}
try
{
// here we logon and register our nickname and so on
irc.Login("test", "test");
// join the channel
irc.RfcJoin(channel);
irc.SendMessage(SendType.Message, "test", "!query");
// here we tell the IRC API to go into a receive mode, all events
// will be triggered by _this_ thread (main thread in this case)
// Listen() blocks by default, you can also use ListenOnce() if you
// need that does one IRC operation and then returns, so you need then
// an own loop
irc.Listen();
// when Listen() returns our IRC session is over, to be sure we call
// disconnect manually
irc.Disconnect();
}
catch (Exception e)
{
// this should not happen by just in case we handle it nicely
System.Console.WriteLine("Error occurred! Message: " + e.Message);
System.Console.WriteLine("Exception: " + e.StackTrace);
}
}
}
IrcBot bot = new IrcBot();
bot.RunCommand();
ViewBag.IRC = bot.Data;
As you can see, once this
Thank you for your time to look at this code and read my problem description. If you have any thoughts, or other suggestions, please let me know.
Mike
I was able to successfully disconnect straight away by calling RfcQuit() within OnQueryMessage(), before irc.Disconnect();

How to join received multipart SMS ( GSM Modem )( C# )

I'm programming an app that receives Short Messages (SMS) from a GSM Modem (ZTE Corporation) (+CMTI notifications).
I've already done my program but when there is a multi-part SMS I can not connect them to each other, and all of them come in separate messages.(e.g a 3 part message comes in 3 different messages). how can I connect them and understand which one is after which one? (Consider Someone Sends me two 3-part messages one after another, How can I distinguish these two messages?)
Programming language: C#
SMS in Text Mode (AT+CMGF=1)
I found it, by PDU Header I can find that if there is more smss and with user data header in that i can distinguish packets.
// for gsmcomm users
List<string> messagesList = new List<messageList>();
List<SmsPdu> multiPartMsg = new List<SmsPdu>();
foreach (var i in modem.ReadMessages(PhoneMessageStatus.All, PhoneStorageType.Phone))
{
string msg;
if (SmartMessageDecoder.IsPartOfConcatMessage(((SmsDeliverPdu)i.Data)))
{
multiPartMsg.Add(i.Data);
try
{
if (SmartMessageDecoder.AreAllConcatPartsPresent(multiPartMsg))
{
msg= SmartMessageDecoder.CombineConcatMessageText(multiPartMsg);
messagesList.Add(msg);
multiPartMsg.Clear();
}
}
catch (Exception ex) {}
}
else
{
msg = ((SmsDeliverPdu)i.Data).UserDataText;
messagesList.Add(msg);
}
}
Yes, I tried Nokia's Smart Messaging Concept, for concatenating multi-part messages, but seemed many problems. So finally I found PDU header with some important things like...
If your message is multi-part you can check through
bool Is_Multi_PART = SmartMessageDecoder.IsPartOfConcatMessage(SMSPDU);
see here...
DecodedShortMessage[] messages = comm.ReadMessages(PhoneMessageStatus.All, storage);
foreach (DecodedShortMessage message in messages)
{
GsmComm.PduConverter.SmsDeliverPdu SMSPDU;
SMSPDU = (GsmComm.PduConverter.SmsDeliverPdu)message.Data;
bool Is_Multi_PART = SmartMessageDecoder.IsPartOfConcatMessage(SMSPDU);
byte[] element1 = message.Data.UserData;
if (element1[0] == 5)
{
byte[] numArray = new byte[2];
numArray[0] = element1[3];
numArray[1] = element1[2];
int referenceNumber = BitConverter.ToUInt16(numArray, 0);
int totalMessages = element1[4];
int currentNumber = element1[5];
}
}
Also if your message is multi-part message it should always contain PDU Header with...
Reference Number.
Total Messages (Message/160).
Current Number of Message. (if you have 1 message with 250 length then its simultaneously 1,2).

Categories