I am currently making a client and server. The server will store people and their location using a dictionary. The client can then lookup a location or update/add a person and their location.
For example, I could type 'Lucy', 'School', and the server will add that to the dictionary. If I then type 'Lucy' it should reply with 'School' and if I type in 'Lucy' 'Home' it should up date that to the dictionary.
Currently however, it is not adding people to the dictionary or updating their location. The following is my code to run the server, which is called in the main class:
static void runServer()
{
TcpListener listener;
Socket connection;
NetworkStream socketStream;
try
{
listener = new TcpListener(IPAddress.Any, 43);
listener.Start();
Console.WriteLine("Server started listening");
while (true)
{
connection = listener.AcceptSocket();
socketStream = new NetworkStream(connection);
Console.WriteLine("Connection Recieved.");
doRequest(socketStream);
socketStream.Close();
connection.Close();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.ToString());
}
}
This part is the doRequest method which is called in the runServer. This is where I have made my dictionary and tried methods to update and add:
static void doRequest(NetworkStream socketStream)
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
try
{
socketStream.ReadTimeout = 1000;
socketStream.WriteTimeout = 1000;
StreamWriter sw = new StreamWriter(socketStream);
StreamReader sr = new StreamReader(socketStream);
String line = sr.ReadLine().Trim();
String[] Sections = line.Split(new char[] {' '}, 2);
if (Sections.Length == 1)
{
if (dictionary.ContainsKey(Sections[0]))
{
sw.WriteLine(dictionary[Sections[0]]);
sw.Flush();
}
else
{
sw.WriteLine("ERROR: no entries found");
sw.Flush();
}
}
else if (Sections.Length == 2)
{
try
{
if (dictionary.ContainsKey(Sections[0]))
{
dictionary[Sections[0]] = Sections[1];
sw.WriteLine("OK");
sw.Flush();
}
else
{
dictionary.Add(Sections[0], Sections[1]);
sw.WriteLine("OK");
sw.Flush();
}
}
catch
{
sw.WriteLine("DIDNT SAVE");
}
}
else
{
sw.WriteLine("Too many arguments");
}
}
catch
{
Console.WriteLine("Unable to connect");
}
}
I've tried various different ways. My first concern was that the dictionary is created in the dorequest method so isn't global, however it doesn't seem to work when I put it somewhere else.
Hopefully it's just a little mistake I've missed.
Any help would be largely appreciated.
Thanks
Lucy
Related
I'm using the following code to test if SQL Server is running, and I'm facing a strange behavior, the result is true only if I set a breakpoint under that statement, otherwise it will return false. My timeout value is set to 120.
public static bool IsServerRunning()
{
string[] serverDetails= serverName.Split(',');
string fullServerName = serverDetails[0];
string[] stringSeparators = new string[] { "\\" };
string[] fullServerNameDetails = fullServerName.Split(stringSeparators, StringSplitOptions.None);
string serverIpAdress = fullServerNameDetails[0];
int serverPort = int.Parse(serverDetails[1]);
int timeout = GetRemoteServerTimeout();
var result = false;
try
{
using ( var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, Sockets.ProtocolType.Tcp) )
{
IAsyncResult asyncResult = socket.BeginConnect(serverIpAdress, serverPort, null, null);
result = asyncResult.AsyncWaitHandle.WaitOne(timeout, true);
socket.Close();
}
return result;
}
catch ( Exception myException )
{
return false;
}
}
UPDATE:
I've found a working solution, however I'm not sure if it the most safe/reliable way to implement it.
private static bool IsServerRunning()
{
try
{
using (var sqlConnection = new SqlConnection(GetConnectionString()))
{
sqlConnection.Open();
return true;
}
}
catch (Exception ex)
{
log.Error("Error message for connection failed " + ex.Message);
return false;
}
I am not an expert in c# but it looks like using IAsyncResult you return the result before the result actually get set. why dont you use this more simplistic solution posted by #RameshDurai here
Below is one method that basically sends the data to TCP Server.
UPDATE BEGINS HERE:
//////////////////////////////////
private string FormatValueByPresentation(IBuffer buffer, GattPresentationFormat format)
{
// BT_Code: For the purpose of this sample, this function converts only UInt32 and
// UTF-8 buffers to readable text. It can be extended to support other formats if your app needs them.
byte[] data;
CryptographicBuffer.CopyToByteArray(buffer, out data);
if (format != null)
{
if (format.FormatType == GattPresentationFormatTypes.UInt32 && data.Length >= 4)
{
return BitConverter.ToInt32(data, 0).ToString();
}
else if (format.FormatType == GattPresentationFormatTypes.Utf8)
{
try
{
return Encoding.UTF8.GetString(data);
}
catch (ArgumentException)
{
return "(error: Invalid UTF-8 string)";
}
}
else
{
// Add support for other format types as needed.
return "Unsupported format: " + CryptographicBuffer.EncodeToHexString(buffer);
}
}
else if (data != null)
{
// We don't know what format to use. Let's try some well-known profiles, or default back to UTF-8.
if (selectedCharacteristic.Uuid.Equals(GattCharacteristicUuids.HeartRateMeasurement))
{
try
{
///////LOOK HERE/////
**string b = ParseHeartRateValue(data).ToString();
TrySend(b);
//return "Heart Rate: " + ParseHeartRateValue(data).ToString();
return "Heart Rate: " + b;**
}
catch (ArgumentException)
{
return "Heart Rate: (unable to parse)";
}
}
else if (selectedCharacteristic.Uuid.Equals(GattCharacteristicUuids.BatteryLevel))
{
try
{
// battery level is encoded as a percentage value in the first byte according to
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.battery_level.xml
return "Battery Level: " + data[0].ToString() + "%";
}
catch (ArgumentException)
{
return "Battery Level: (unable to parse)";
}
}
// This is our custom calc service Result UUID. Format it like an Int
else if (selectedCharacteristic.Uuid.Equals(Constants.ResultCharacteristicUuid))
{
return BitConverter.ToInt32(data, 0).ToString();
}
// No guarantees on if a characteristic is registered for notifications.
else if (registeredCharacteristic != null)
{
// This is our custom calc service Result UUID. Format it like an Int
if (registeredCharacteristic.Uuid.Equals(Constants.ResultCharacteristicUuid))
{
return BitConverter.ToInt32(data, 0).ToString();
}
}
else
{
try
{
return "Unknown format: " + Encoding.UTF8.GetString(data);
}
catch (ArgumentException)
{
return "Unknown format";
}
}
}
else
{
return "Empty data received";
}
return "Unknown format";
}
///////// END OF UPDATE //////
private async void TrySend(string data)
{
// Create the StreamSocket and establish a connection to the echo server.
StreamSocket socket = new StreamSocket();
try
{
var streamSocket = new Windows.Networking.Sockets.StreamSocket();
{
//The server hostname that we will be establishing a connection to. In this example, the server and client are in the same process.
var hostName = new Windows.Networking.HostName("127.0.0.1");
await streamSocket.ConnectAsync((new Windows.Networking.HostName("127.0.0.1")), "9999");
// Send a request to the echo server.
using (Stream outputStream = streamSocket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
while (true)
{
await streamWriter.WriteLineAsync(data);
await streamWriter.FlushAsync();
}
//await streamWriter.WriteLineAsync(data);
//await streamWriter.FlushAsync();
}
}
}
}
catch (Exception)
{
}
}
And here is my TCP Server code that receives the data:
public class EchoServer {
public static void Main() {
TcpListener listener = null;
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 9999);
listener.Start();
Console.WriteLine("TCP Server Has Started....");
while (true)
{
Console.WriteLine(" ");
Console.WriteLine("Waiting for incoming client connections....");
Console.WriteLine(" ");
Console.WriteLine("A message will display below once the client starts and establishes a connection ");
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine(" ");
Console.WriteLine("Okay, Accepting Client connection now");
Console.WriteLine(" ");
Console.WriteLine("Accepted new client connection.....");
StreamReader reader = new StreamReader(client.GetStream());
StreamWriter writer = new StreamWriter(client.GetStream());
string s = string.Empty;
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null)) {
Console.WriteLine("From client -> " + s);
writer.WriteLine("From server -> " + s);
writer.Flush();
}
reader.Close();
writer.Close();
client.Close();
}
} catch (Exception e)
{
Console.WriteLine(e);
} finally
{
if (listener != null)
{
listener.Stop();
}
}
}
}
Now, the data I am trying to get are the heart rates and it changes every two seconds. However on TCP server I only get the first recorded value of a heart rate and it keeps repeating instead of getting new one.
There is a similar post I saw here on stackoverflow : UWP TCP receive data continuously
and someone suggested to use while loop which I did as you can see in the code.
Are there any other suggestions on what should I do?
Thanks
while (true)
{
await streamWriter.WriteLineAsync(data);
await streamWriter.FlushAsync();
}
The while(true) will keep repeating, meaning that it will always send 'data' at its current value. This is what causes your issue.
In my opinion, you should keep a connection to your TCP server open outside of your 'TrySend' method, and use this method only to send the data. This way you won't need to use this loop.
EDIT :
Try this :
private async void CharacteristicReadButton_Click()
{
while(true)
{
// BT_Code: Read the actual value from the device by using Uncached.
GattReadResult result = await selectedCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (result.Status == GattCommunicationStatus.Success)
{
string formattedResult = FormatValueByPresentation(result.Value, presentationFormat);
rootPage.NotifyUser($"Read result: {formattedResult}", NotifyType.StatusMessage);
//string formattedResult = FormatValueByPresentation(result.Value, presentationFormat);
//rootPage.NotifyUser($"Read result: {formattedResult}", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser($"Read failed: {result.Status}", NotifyType.ErrorMessage);
}
}
}
I have an OPC-DA Server that a SCADA software writes the variables and its values in it so I want to read them synchronously with using C#. I have already write my algorithm but I could not read the variables. The code creates a subscription or may be creates a group instance that writes the own variables and values in it but I do not want this. I need to just read the values from OPC server.
I have established a connection between OPC Server but I have not reach the variables which writes the variables into OPC Server.
Where is the problem, I cannot realise it. Could you suggest a solution about it?
My Code:
class OpcFunctions
{
Opc.Da.Server Server = null;
OpcCom.Factory Factory = new OpcCom.Factory();
Opc.Da.Item[] Items;
Opc.Da.Subscription Group;
Opc.IRequest myReq;
Opc.Da.WriteCompleteEventHandler WriteEventHandler;
Opc.Da.ReadCompleteEventHandler ReadEventHandler;
public void GetOpcServers(TreeView OpcServerTreeList, ListBox OpcConnectionUrlListBox)
{
try
{
OpcCom.ServerEnumerator myServerEnumerator = new OpcCom.ServerEnumerator();
Opc.Server[] Servers = myServerEnumerator.GetAvailableServers(Opc.Specification.COM_DA_20);
ListServers(Servers,OpcServerTreeList,OpcConnectionUrlListBox);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ListServers(Opc.Server[] OpcServerList , TreeView OpcServerTreeList, ListBox OpcConnectionUrlListBox)
{
try
{
OpcServerTreeList.Nodes.Clear();
OpcConnectionUrlListBox.Items.Clear();
foreach(Opc.Server myServer in OpcServerList)
{
TreeNode myTreeNode = new TreeNode(myServer.Name);
myTreeNode.Nodes.Add(myServer.Url.HostName + ":" + myServer.Url.Path + ":" + myServer.Url.Port);
myTreeNode.Nodes.Add(myServer.Url.ToString());
myTreeNode.Nodes.Add(myServer.IsConnected.ToString());
OpcServerTreeList.Nodes.Add(myTreeNode);
OpcConnectionUrlListBox.Items.Add(myServer.Url.ToString());
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public bool ConnectOpcServer(string OpcUrl)
{
Opc.URL Url = new Opc.URL(OpcUrl);
Server = new Opc.Da.Server(Factory, null);
try
{
Server.Connect(Url, new Opc.ConnectData(new System.Net.NetworkCredential()));
Opc.Da.SubscriptionState GroupState = new Opc.Da.SubscriptionState();
GroupState.Name = "Group1";
GroupState.Active = true;
Group = (Opc.Da.Subscription)Server.CreateSubscription(GroupState);
Group.DataChanged += new Opc.Da.DataChangedEventHandler(GroupDataChanged);
Items = Group.AddItems(Items);
ReadEventHandler = new Opc.Da.ReadCompleteEventHandler(ReadCompleteCallback);
Group.Read(Group.Items, 123, ReadCompleteCallback, out myReq);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
return true;
}
void GroupDataChanged(object subscriptionHandle, object requestHandle, Opc.Da.ItemValueResult[] values)
{
uint order = 1;
foreach (Opc.Da.ItemValueResult chitem in values)
{
myWriteLogList(order, chitem.Timestamp, chitem.ItemName, chitem.Value.ToString(), chitem.Quality.ToString());
++order;
}
}
void myWriteLogList(uint order, DateTime timestamp, string name, string value, string signalquality)
{
SettingsUI.OpcExplorer.dataGridViewOpcExplorer.BeginInvoke((MethodInvoker)delegate
{
SettingsUI.OpcExplorer.dataGridViewOpcExplorer.Rows.Add(null,order,timestamp,name,value,signalquality);
});
}
void ReadCompleteCallback(object clientHandle, Opc.Da.ItemValueResult[] results)
{
uint order = 1;
foreach (Opc.Da.ItemValueResult readResult in results)
{
myWriteLogList(order, readResult.Timestamp, readResult.ItemName, readResult.Value.ToString(), readResult.Quality.ToString());
++order;
}
}
}
Your 'Items' is empty!
sample:
Opc.Da.Item[] items = new Opc.Da.Item[1];
items[0] = new Opc.Da.Item();
items[0].ItemName = "PlcGroup.Items.value";
Try read from server...
ADD ITEMS AND READ
var result=Server.read(items);
For(i=0;i<result.length;i++) { Console.writeln(result[i].value); }
I'm sorry if I'm asking something asked before.
I'm developing a program that reads data received via TCP and using a StreamReader, and I just can't find how to make sure that any data won't be missed. Is there any way to create a middle buffer to read from there or something like that?
Here are the methods I've created for receiving data and write it to a text box:
public static void Connect(string IP, string port)
{
try
{
client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse(IP), int.Parse(port));
client.Connect(IP_End);
if (client.Connected)
{
connected = "Connected to Exemys!" + "\r\n";
STR = new StreamReader(client.GetStream());
bgWorker = true;
}
}
catch (Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
-
public static void MessageReceiving(TextBox textBox)
{
try
{
string values =Conection.STR.ReadLine();
textBox.Invoke(new MethodInvoker(delegate () { textBox.AppendText("Exemys : " + values.Substring(2) + Environment.NewLine); }));
try
{
string messagetype = values.Substring(5, 1);
string ID = values.Substring(3, 2);
string checksum = values.Substring(values.Length - 2, 2);
if (checksum == CalcularChecksum(values.Substring(3, values.Length - 5)))
{
if (messagetype == "N")
{
if (ID == "01")
{
ID1 = values.Substring(3, 2);
messagetype1 = values.Substring(5, 1);
capacity1 = values.Substring(6, 1);
pressure1 = values.Split(',')[1];
sequencetime1 = values.Split(',')[2];
runstatus1 = values.Split(',')[3];
mode1 = values.Split(',')[4].Substring(0, 1);
checksum1 = CalcularChecksum(values.Substring(3, values.Length - 5));
}
if (ID == "02")
{
ID2 = values.Substring(3, 2);
messagetype2 = values.Substring(5, 1);
capacity2 = values.Substring(6, 1);
pressure2 = values.Split(',')[1];
sequencetime2 = values.Split(',')[2];
runstatus2 = values.Split(',')[3];
mode2 = values.Split(',')[4].Substring(0, 1);
checksum2 = CalcularChecksum(values.Substring(3, values.Length - 5));
}
}
}
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
catch (Exception)
{
MessageBox.Show("Client disconnected.");
}
}
Edit: what I'm trying to ask is how to always process the entire data before continue receiving? That would be the question.
A TCP stream is a stream of bytes that ends when the socket is closed by you or the remote peer or breaks because of network issues. In order to get everything from the stream you need to call the StreamReader.ReadLine method inside a loop into a buffer until some stop condition applies.
...
try
{
while(true)
{
...
input = STR.ReadLine();
if (input == <some stop condition>)
break;
...
}
}
...
That's a highly simplified example. TCP reading with partial buffer handling can be a complex beast so I recommend to use a library or framework if you're doing more than some hobby project.
Thanks for the response, but after searching, I've found what I was looking for. I wanted to store those messages (data) that were entering to make sure that I won't lose them (for any reason, more precisely that the receiving process would be faster than the message processing operation), so I used Queue to achieve this.
public static void RecepcionMensajes(TextBox textBox)
{
if (client.Connected == true)
{
try
{
string fifo = Conexion.STR.ReadLine();
Queue mensajes = new Queue();
//AquĆ se ponen en cola los mensajes que van llegando, utilizando el sistema FIFO.
mensajes.Enqueue(fifo);
string values = mensajes.Dequeue().ToString();
textBox.Invoke(new MethodInvoker(delegate () { textBox.AppendText("Exemys : " + values.Substring(2) + Environment.NewLine); }));
I have a telephony application, in which I want to invoke simultaneous calls,. Each call will occupy a channel or port. So I added all channels to a BlockingCollection. The application is a windows service.
Let's see the code.
public static BlockingCollection<Tuple<ChannelResource, string>> bc = new BlockingCollection<Tuple<ChannelResource, string>>();
public static List<string> list = new List<string>();// then add 100 test items to it.
The main application has the code:
while (true)
{
ThreadEvent.WaitOne(waitingTime, false);
lock (SyncVar)
{
Console.WriteLine("Block begin");
for (int i = 0; i < ports; i++)
{
var firstItem = list.FirstOrDefault();
if (bc.Count >= ports)
bc.CompleteAdding();
else
{
ChannelResource cr = OvrTelephonyServer.GetChannel();
bc.TryAdd(Tuple.Create(cr, firstItem));
list.Remove(firstItem);
}
}
pc.SimultaneousCall();
Console.WriteLine("Blocking end");
if (ThreadState != State.Running) break;
}
Now for the simultaneous call code:
public void SimultaneousCall()
{
Console.WriteLine("There are {0} channels to be processed.", bc.Count);
var workItemBlock = new ActionBlock<Tuple<ChannelResource, string>>(
workItem =>
{
ProcessEachChannel(workItem);
});
foreach (var workItem in bc.GetConsumingEnumerable())
{
bool result = workItemBlock.SendAsync(workItem).Result;
}
workItemBlock.Complete();
}
private void ProcessEachChannel(Tuple<ChannelResource, string> workItem)
{
ChannelResource cr = workItem.Item1;
string sipuri = workItem.Item2;
VoiceResource vr = workItem.Item1.VoiceResource;
workItem.Item1.Disconnected += new Disconnected(workItemItem1_Disconnected);
bool success = false;
try
{
Console.WriteLine("Working on {0}", sipuri);
DialResult dr = new DialResult();
// blah blah for calling....
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
finally
{
if (cr != null && cr.VoiceResource != null)
{
cr.Disconnect();
cr.Dispose();
cr = null;
Console.WriteLine("Release channel for item {0}.", sipuri);
}
}
}
The question was when I tested the application with 4 ports, I thought the code should reach at
Console.WriteLine("Blocking end");
However it was not. Please see the snapshot.
The application is just hanging on after releasing the last channel. I guess that I may use the blockingcollection incorrectly. Thanks for help.
UPDATE:
Even I changed the code by using POST action as below, the situation is still unchanged.
private bool ProcessEachChannel(Tuple<ChannelResource, string> workItem)
{
// blah blah to return true or false respectively.
public void SimultaneousCall()
{
Console.WriteLine("There are {0} channels to be processed.", bc.Count);
var workItemBlock = new ActionBlock<Tuple<ChannelResource, string>>(
workItem =>
{
bool success = ProcessEachChannel(workItem);
});
foreach (var workItem in bc.GetConsumingEnumerable())
{
workItemBlock.Post(workItem);
}
workItemBlock.Complete();
}
I believe the problem is that you never call bc.CompleteAdding(): the if means it would be called in ports + 1-th iteration of the loop, but the loop iterates only ports-times. Because of this, GetConsumingEnumerable() returns a sequence that never ends, which means the foreach inside SimultaneousCall() blocks forever.
I think the right solution is to call bc.CompleteAdding() after the for loop, not in an impossible condition inside it.