C# multi-thread ping - c#

I'm working on a network monitoring application, that pings a (not known) number of hosts. So far I have the code below. I've made a class PingHost with a function zping and I called it with the help of a timer once every 2 seconds to let the 2 pings to finish, even if one of them gets TimedOut. But I think a better solution is to generate a new thread for every ping, so that the ping of every host would be independent.
Can anyone give me a hint how to do this?
namespace pinguin
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
PingHost caca = new PingHost();
PingHost caca1 = new PingHost();
this.label1.Text = caca.zping("89.115.14.160");
this.label2.Text = caca1.zping("89.115.14.129");
}
}
public class PingHost
{
public string zping(string dest)
{
Application.DoEvents();
Ping sender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 50;
int failed = 0;
int pingAmount = 5;
string stat = "";
PingReply reply = sender.Send(dest, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
stat = "ok";
}
else
{
stat = "not ok!";
}
return stat;
}
}
}

If you use .NET 4 you can use Parallel.Invoke.

You could handle the Ping.PingCompleted event:
ping.PingCompleted += new PingCompletedEventHandler(ping_PingCompleted);
then use:
ping.SendAsync()
side note: Choose more suitable names for your classes and routines. PingHost is more suitable as a routine name

Once I wrote such a solution (it constantly pings about 300 machines):
public class ManyAdressPing {
private readonly bool bAutoStarted;
private readonly CancellationTokenSource cancel = new CancellationTokenSource();
public ConcurrentDictionary<IPAddress, OneAddressPing> pingi = new ConcurrentDictionary<IPAddress, OneAddressPing>();
public ManyAdressPing(bool AutoStarted = true) {
bAutoStarted = AutoStarted;
}
public int CountPings => pingi.Count;
public void AddPingAddress(IPAddress addr, int msTimeOut = 3000, int BetweenPing = 3000) {
var oap = new OneAddressPing(addr, cancel.Token, msTimeOut, BetweenPing);
if (bAutoStarted) oap.Start();
pingi.TryAdd(oap.ipAddress, oap);
}
public void RemovePingAddress(IPAddress addr) {
if (pingi.TryRemove(addr, out var p)) p.Stop();
}
public void Stop() {
cancel.Cancel();
foreach (var pair in pingi) pair.Value.Stop();
}
public PingReply GetReply(IPAddress addr) {
if (pingi.ContainsKey(addr)) return pingi[addr].GetReply();
return null;
}
public Tuple<long, long> GetSuccessOperation(IPAddress addr) {
if (pingi.ContainsKey(addr)) return pingi[addr].GetSuccessOperation();
return null;
}
public PingReply[] GetReply() {
PingReply[] ret = pingi.Values.Select(x=>x.GetReply()).ToArray();
return ret;
}
public PingInfo GetPingInfo(IPAddress addr) {
if (pingi.ContainsKey(addr)) {
var ret = new PingInfo();
var p = pingi[addr];
ret.reply = p.GetReply();
ret.SuccessPing = p._SuccessReply;
ret.FailPing = p._FailReply;
ret.LastSuccessPing = p.LastSuccessfullPing;
return ret;
}
return null;
}
public bool IsPinged(IPAddress addr) {
if (pingi.ContainsKey(addr)) return true;
return false;
}
public IPAddress[] GetAddressesPing() {
return pingi.Keys.ToArray();
}
}
public class PingInfo {
public PingReply reply;
public long SuccessPing = 0;
public long FailPing = 0;
public DateTime LastSuccessPing;
public override string ToString() {
return $"Sping: {SuccessPing} last={LastSuccessPing}, Fping:{FailPing}, reply:{reply}";
}
}
public class OneAddressPing {
public static byte[] bu = {
0
};
public long _FailReply;
public long _SuccessReply;
private bool bStop = false;
private readonly CancellationToken cancellationToken;
public DateTime LastSuccessfullPing = DateTime.MinValue;
public int mSecBetweenPing = 3000;
public Ping ping;
public PingOptions popt;
private Task pTask;
// Here is a self-written LIFO stack
public LightQueue<PingReply> replys = new LightQueue<PingReply>(10);
private readonly AutoResetEvent reset = new AutoResetEvent(false);
private Logger log = null;
private Task pinging = null;
public OneAddressPing(IPAddress addr, CancellationToken ct, int timeOut = 3000, int BetweenPing = 3000, Logger _log =null) {
ipAddress = addr;
popt = new PingOptions();
popt.DontFragment = false;
cancellationToken = ct;
mSecTimeOut = timeOut;
mSecBetweenPing = BetweenPing;
log = _log;
}
public int mSecTimeOut { get; set; } = 3000;
public IPAddress ipAddress { get; set; }
public int CountPings => replys.Length;
private void SetReply(PingReply rep) {
if (rep == null) return;
replys.Put(rep);
if (rep.Status == IPStatus.Success) {
Interlocked.Increment(ref _SuccessReply);
LastSuccessfullPing = DateTime.Now;
} else {
Interlocked.Increment(ref _FailReply);
}
}
public async Task Start() {
if (pTask == null || pTask.Status != TaskStatus.Running) {
ping = new Ping();
Task.Factory.StartNew(PingCircle, TaskCreationOptions.RunContinuationsAsynchronously | TaskCreationOptions.LongRunning); pTask = Task.Run(PingCircle, cancellationToken);
}
}
public void Stop() {
if (pTask.Status == TaskStatus.Running) {
bStop = true;
try {
pTask.Wait(mSecTimeOut, cancellationToken);
} catch (Exception ex) {
log.ErrorSource($"Error ping stop: {ex.Message}");
}
}
}
private async Task PingCircle() {
while (cancellationToken.IsCancellationRequested == false && !bStop) {
try {
try {
PingReply rep = await ping.SendPingAsync(ipAddress, mSecTimeOut, bu,popt);
if (rep != null) SetReply(rep);
} catch (PingException p) {
// ignore ping error
Debug.WriteLine($"error: {p}");
} catch (Exception ee) {
log?.ErrorSource(ee);
Debug.WriteLine($"error: {ee}");
}
await Task.Delay(mSecBetweenPing, cancellationToken);
} catch (Exception ee) {
log?.ErrorSource(ee);
}
}
}
public PingReply GetReply() {
if (replys.IsEmpty) return null;
return replys.PeekLast(0);
}
public Tuple<long, long> GetSuccessOperation() {
return new Tuple<long, long>(_SuccessReply, _FailReply);
}
public bool LongPingSuccess() {
int ret = 0;
for (int i = 0; i < 5; i++) {
var r = replys.PeekLast(i);
if (r.Status == IPStatus.Success) ret++;
}
if (ret > 2) return true;
return false;
}
}

Related

Why isn't it possible to read my byteBuffer String out?(c#)

I wrote a basic server client program with c# and Unity to create my own network. During the process I wrote a byteBuffer to send data over the network. Everything works, but to send or receive the String. (I can send Integers and other dataforms succesfully).
My DLL file:
public class ByteBuffer : IDisposable
{
private List<byte> Buff;
private byte[] readBuff;
private int readpos;
private bool buffUpdated;
private bool disposedValue;
#region "Helpers"
public ByteBuffer()
{
this.buffUpdated = false;
this.disposedValue = false;
this.Buff = new List<byte>();
this.readpos = 0;
}
public long GetReadPos() =>
((long)this.readpos);
public byte[] ToArray() =>
this.Buff.ToArray();
public int Count() =>
this.Buff.Count;
public int Length() =>
(this.Count() - this.readpos);
public void Clear()
{
this.Buff.Clear();
this.readpos = 0;
}
#endregion
#region"Write Data"
public void WriteByte(byte Inputs)
{
Buff.Add(Inputs);
buffUpdated = true;
}
public void WriteBytes(byte[] Input)
{
this.Buff.AddRange(Input);
this.buffUpdated = true;
}
public void WriteInteger(int Input)
{
this.Buff.AddRange(BitConverter.GetBytes(Input));
this.buffUpdated = true;
}
public void WriteString(string Input)
{
this.Buff.AddRange(BitConverter.GetBytes(Input.Length));
this.Buff.AddRange(Encoding.ASCII.GetBytes(Input));
this.buffUpdated = true;
}
#endregion
#region "read Data"
public string ReadString(bool Peek = true)
{
int count = this.ReadInteger(true);
if (this.buffUpdated)
{
this.readBuff = this.Buff.ToArray();
this.buffUpdated = false;
}
string str = Encoding.ASCII.GetString(this.readBuff, this.readpos, count);
if ((Peek & (this.Buff.Count > this.readpos)) && (str.Length > 0))
{
this.readpos += count;
}
return str;
}
public byte ReadByte(bool Peek = true)
{
if (Buff.Count > readpos)
{
if (buffUpdated)
{
readBuff = Buff.ToArray();
buffUpdated = false;
}
byte ret = readBuff[readpos];
if (Peek & Buff.Count > readpos)
{
readpos += 1;
}
return ret;
}
else
{
throw new Exception("Byte Buffer is past its Limit!");
}
}
public byte[] ReadBytes(int Length, bool Peek = true)
{
if (this.buffUpdated)
{
this.readBuff = this.Buff.ToArray();
this.buffUpdated = false;
}
byte[] buffer = this.Buff.GetRange(this.readpos, Length).ToArray();
if (Peek)
{
this.readpos += Length;
}
return buffer;
}
public int ReadInteger(bool peek = true)
{
if (this.Buff.Count <= this.readpos)
{
throw new Exception("Byte Buffer Past Limit!");
}
if (this.buffUpdated)
{
this.readBuff = this.Buff.ToArray();
this.buffUpdated = false;
}
int num = BitConverter.ToInt32(this.readBuff, this.readpos);
if (peek & (this.Buff.Count > this.readpos))
{
this.readpos += 4;
}
return num;
}
#endregion
//IDisposable
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if(disposing)
{
this.Buff.Clear();
}
this.readpos = 0;
}
this.disposedValue = true;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}
My SendData Class:
class ServerSendData{
public static ServerSendData instance = new ServerSendData();
public void SendDataToClient(int index, byte[] data)
{
ByteBuffer.ByteBuffer buffer = new ByteBuffer.ByteBuffer();
buffer.WriteBytes(data);
Network.Clients[index].myStream.BeginWrite(buffer.ToArray(), 0, buffer.ToArray().Length, null, null);
buffer = null;
}
public void SendWelcomeMessage(int index)
{
ByteBuffer.ByteBuffer buffer = new ByteBuffer.ByteBuffer();
buffer.WriteInteger(1); //paket nummer 1
buffer.WriteByte(2);
buffer.WriteString("A");
SendDataToClient(index, buffer.ToArray());
}
}
My HandleData Class:
public class ClientHandleData: MonoBehaviour{
public void HandleData(byte[]data)
{
int packetNum;
ByteBuffer.ByteBuffer buffer = new ByteBuffer.ByteBuffer();
buffer.WriteBytes(data);
packetNum = buffer.ReadInteger();
buffer = null;
if (packetNum == 0)
{
return;
}
else
{
HandleMessages(packetNum, data);
}
}
public void HandleMessages(int packetNum, byte[] data)
{
switch (packetNum)
{
case 1:
HandleWelcomeMessage(data);
break;
}
}
public void HandleWelcomeMessage(byte[] data)
{
ByteBuffer.ByteBuffer buffer = new ByteBuffer.ByteBuffer();
buffer.WriteBytes(data);
Debug.Log("Test");
int nummer = buffer.ReadInteger();
Debug.Log("Test1: "+nummer);
byte bt = buffer.ReadByte();
Debug.Log("Test2: " +bt);
message = buffer.ReadString();
Debug.Log("Test3");
Debug.Log(nummer);
Debug.Log(message);
Debug.Log(bt);
buffer = null;
}
}
My Log result looks like:
Test
Test1: 1
Test2: 2
Working with Unity 2018.2.11f1 personal 64 bit

Timer in SignalR overlaps when another group enters into hub

I have created a signalR hub which is solving purpose to show timer at UI of grouped person. If one person starts a play with another one, timer runs very nice.
But the problem is when another group start a new play and previous one is still in progress, I mean Timer is already running, then it overlaps the timer and hold one group. Timer runs once at a time. But I want it to have threading and run for every group.
here is my code:
ConnectionMapping.cs
public class ConnectionMapping<T>
{
private readonly Dictionary<T, HashSet<string>> _connections = new Dictionary<T, HashSet<string>>();
public int Count { get { return _connections.Count; } }
public void Add(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
connections = new HashSet<string>();
_connections.Add(key, connections);
}
lock (connections)
{
connections.Add(connectionId);
}
}
}
public IEnumerable<string> GetConnections(T key)
{
HashSet<string> connections;
if (_connections.TryGetValue(key, out connections))
{
return connections;
}
return Enumerable.Empty<string>();
}
public void Remove(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
return;
}
lock (connections)
{
connections.Remove(connectionId);
if (connections.Count == 0)
{
_connections.Remove(key);
}
}
}
}
}
Below is a Hub class:
public class TimeSyncingHub : Hub
{
private readonly static ConnectionMapping<int> _connections = new ConnectionMapping<int>();
private readonly PlayerPickTicker _playerPickTicker;
private readonly object _PickStateLock = new object();
private IUserBusiness userBusiness;
public TimeSyncingHub() :
this(PlayerPickTicker.Instance)
{
}
public TimeSyncingHub(PlayerPickTicker playerPickTicker)
{
_playerPickTicker = playerPickTicker;
}
public Task LeaveRoom(string roomName)
{
return Groups.Remove(Context.ConnectionId, roomName);
}
public async Task JoinRoom(string roomName)
{
await Groups.Add(Context.ConnectionId, roomName);
Clients.Group(roomName).JoinedRoom("Enter into group - " + roomName);
}
}
Another class where I have written time code is PlayerPickTicker class which is depends in same and implemented in constructor of hub class as shown in class above.
Below is PlayerPickTicker class:
public class PlayerPickTicker : IDisposable
{
private readonly static Lazy<PlayerPickTicker> _instance = new Lazy<PlayerPickTicker>(
() => new PlayerPickTicker(GlobalHost.ConnectionManager.GetHubContext<TimeSyncingHub>()));
private IHubContext _context;
public UserPlayerPickModel UserPlayerPick { get; set; }
public static PlayerPickTicker Instance { get { return _instance.Value; } }
private Timer TickTimer;
private Timer InitialTickTimer;
public int StartSeconds { get; set; }
public int StopSeconds { get; set; }
public bool IsTimerOver { get; set; }
private PlayerPickTicker(IHubContext context)
{
_context = context;
}
public void StartInitialTimer(Model.QueryModel queryModel)
{
try
{
MyDraftBusiness myDraft = new MyDraftBusiness();
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
//lock (_InitialTimerStateLock)
//{
//StartSeconds = 60;
//if (InitialTickTimer != null)
//{
// InitialTickTimer.Dispose();
//}
States = new Dictionary<string, bool>() {
{ "IsInitialTimerOver", false},
{ "CallInitialTimerOverMethod", true},
};
PickPlayer = new Dictionary<string, long>() { { "LastPlayerPickId", 0 } };
//lock (States)
//{
StartSeconds = 60;
StopSeconds = 0;
IsInitialTimerOver = false;
CallInitialTimerOverMethod = true;
//}
InitialTickTimer = new Timer();// OnTimerElapsedInitialTimer, queryModel, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
InitialTickTimer.Interval = 1000;
InitialTickTimer.Enabled = true;
InitialTickTimer.Elapsed += (sender, e) => OnTimerElapsedInitialTimer(queryModel, e);
InitialTickTimer.AutoReset = false;
//}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At StartInitialTimer Mehtod )- " + ex.Message);
}
}
private void OnTimerElapsedInitialTimer(object sender, ElapsedEventArgs e)
{
Model.QueryModel queryModel = (Model.QueryModel)sender;
try
{
//lock (_InitialtickStateLock)
//{
var states = (Dictionary<string, bool>)States;
var IsInitialTimerOver = states.FirstOrDefault(x => x.Key == "IsInitialTimerOver").Value;
//Clients.
if (StartSeconds <= StopSeconds && !IsInitialTimerOver)
{
if (InitialTickTimer != null)
{
InitialTickTimer.Dispose();
}
//IsInitialTimerOver = true;
states["IsInitialTimerOver"] = true;
//lock (States)
//{
//************** from client to server
var JsonResult = new JObject();
JsonResult.Add("data", JToken.FromObject(queryModel));
string GroupName = "Group" + queryModel.playId.ToString();
_context.Clients.Group(GroupName).initialTimerCompleted(JsonResult);
//_context.Clients.Group(GroupName, _context.Clients.All).initialTimerCompleted(JsonResult);
//_context.Clients.All.initialTimerCompleted(JsonResult);
MyDraftBusiness myDraft = new MyDraftBusiness();
try
{
myDraft.UdpatePlaysOneMinuteTimerRunning(queryModel);
DraftModel draftModel = myDraft.GetDraftById(queryModel);
if (draftModel != null)
{
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(draftModel.PlayId);
if (draftModel.IsDraftFilled)
{
if (draftModel.Play != null && draftModel.Play.IsOneMinuteTimerPending == true)
{
myDraft.UdpatePlaysOneMinuteTimerPending(queryModel);
}
else
{
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
}
}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod inner catch )- " + ex.Message);
var userPlayerPicks = myDraft.GetUserPlayerPickByPlayId(queryModel.playId);
var activeUserPick = userPlayerPicks.Where(x => !x.Picked).FirstOrDefault();
if (activeUserPick != null)
{
StartTimer(activeUserPick);
}
}
//}
}
else if (StartSeconds > 0)
{
//IsInitialTimerOver = false;
states["IsInitialTimerOver"] = false;
//lock (States)
//{
StartSeconds -= 1;
var GroupName = "Group" + Convert.ToString(queryModel.playId);
_context.Clients.Group(GroupName).intialTimerElapsed(StartSeconds);
_context.Clients.All.pickRunning(queryModel.playId);
InitialTickTimer.Stop();
InitialTickTimer.Start();
//StartInitialTimer(queryModel);
//}
}
//}
}
catch (Exception ex)
{
Helpers.ExceptionsLog.LogFile(" -( At OnTimerElapsedInitialTimer Mehtod )- " + ex.Message);
}
}
I know it's big code and hard to understand. But I hope for Any Good Developer here, Much appreciation for helper from core of my heart!

C# - Sockets: Port Forwarding [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 6 years ago.
Improve this question
I am working at a Network Program but when I testing the code I find out that my friends (they are not in my local network) cant connect to the server. Now I found out that port forwarding could be the probleme but I dont know how I can change my code, that my friends can connect (when port forwarding the problem is than how can I implement port forwarding in my code).
Here my Classes:
Server class:
static Socket listenerSocket;
static List<ClientData> clients;
static List<ClientName> clientNames;
static List<ClientName> clientReady;
private int port;
public Server(int port)
{
InitializeComponent();
this.port = port;
}
private void Server_Load(object sender, EventArgs e)
{
Start();
}
private void Start()
{
consoleList.Items.Add("Starting Server on " + Packet.GetIP4Address() + ":" + port);
listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clients = new List<ClientData>();
clientNames = new List<ClientName>();
clientReady = new List<ClientName>();
IPEndPoint point = new IPEndPoint(IPAddress.Parse(Packet.GetIP4Address()), port);
try
{
listenerSocket.Bind(point);
}
catch (Exception)
{
MessageBox.Show("Port ist schon benutzt!");
Close();
}
Thread listenThread = new Thread(ListenThread);
listenThread.Start();
}
static void ListenThread()
{
for (;;)
{
listenerSocket.Listen(0);
ClientData data = new ClientData(listenerSocket.Accept());
clients.Add(data);
}
}
public static void ResetReadyClientList()
{
ResetReadyClientList_Server();
}
private static void ResetReadyClientList_Server()
{
clientReady.Clear();
}
public static List<ClientName> GetReadyClientList()
{
return clientReady;
}
public static List<ClientName> GetClientList()
{
return clientNames;
}
public static void Data_IN(object cSocket)
{
Socket clientScoket = (Socket)cSocket;
byte[] buffer;
int readBytes;
for (;;)
{
buffer = new byte[clientScoket.SendBufferSize];
readBytes = clientScoket.Receive(buffer);
if(readBytes > 0)
{
Packet packet = new Packet(buffer);
DataManager(packet);
}
}
}
static List<String> packetsReceived = new List<string>();
static List<String> clientsHasDownloaded = new List<string>();
static String path;
public static void DataManager(Packet p)
{
switch (p.packetType)
{
case PacketType.OutWindow:
String name = GetName(p.senderID);
MessageBox.Show(name + " hat aus dem Fenster geklickt!");
break;
case PacketType.RegisterName:
ClientName cName = new ClientName(p.senderID, p.gData[0]);
clientNames.Add(cName);
break;
case PacketType.Answer:
String senderName = GetName(p.senderID);
String answer = p.gData[0];
MessageBox.Show("Spieler " + senderName + " hat " + answer + " getippt!");
ClientName c = new ClientName(p.senderID, GetName(p.senderID));
if (clientReady.Contains(c)) clientReady.Remove(c);
clientReady.Add(c);
break;
case PacketType.HasDownloaded:
clientsHasDownloaded.Add(p.senderID);
if (clientsHasDownloaded.Count == clients.Count)
{
SoundHostForm form = new SoundHostForm();
form.ShowDialog();
path = p.gData[0];
}
break;
}
}
static ClientData GetClientData(String id)
{
foreach (ClientData c in clients)
{
if(c.id == id)
{
return c;
}
}
return null;
}
public static void SendFileToAll(String path)
{
Thread t = new Thread(() => SendFile(path));
t.Start();
}
private static void SendFile(String path)
{
clientsHasDownloaded.Clear();
Uri downloadLink = FileTransfer.UploadFile(path);
Packet p = new Packet(PacketType.CanDownload, "server");
p.gData.Add(downloadLink.ToString());
foreach (ClientData data in clients)
{
data.clientSocket.Send(p.ToBytes());
}
}
public static void SendPacketToAll(Packet p)
{
foreach(ClientData data in clients)
{
data.clientSocket.Send(p.ToBytes());
}
}
static String GetName(String id)
{
foreach (ClientName c in clientNames)
{
if (c.id == id)
{
return c.name;
}
}
return null;
}
}
class ClientData
{
public Socket clientSocket;
public Thread clientThread;
public String id;
public ClientData()
{
id = Guid.NewGuid().ToString();
clientThread = new Thread(Server.Data_IN);
clientThread.Start(clientSocket);
SendRegisterationPacket();
}
public ClientData(Socket clientSocket)
{
this.clientSocket = clientSocket;
id = Guid.NewGuid().ToString();
clientThread = new Thread(Server.Data_IN);
clientThread.Start(clientSocket);
SendRegisterationPacket();
}
public void SendRegisterationPacket()
{
Packet p = new Packet(PacketType.Registration, "server");
p.gData.Add(id);
clientSocket.Send(p.ToBytes());
}
}
public class ClientName
{
public String id;
public String name;
public ClientName(String id, String name)
{
this.id = id;
this.name = name;
}
}
Client:
public static Socket master;
public string username;
public static string id;
private String ip;
private int port;
public Client(String username, String ipPortString)
{
InitializeComponent();
this.username = username;
ip = ipPortString.Split(':')[0];
port = Convert.ToInt32(ipPortString.Split(':')[1]);
}
private void Client_Load(object sender, EventArgs e){}
public void Start()
{
master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint point = new IPEndPoint(IPAddress.Parse(ip), port);
try
{
master.Connect(point);
}
catch
{
MessageBox.Show("Fehler beim Verbinden! Code: 0x156f237" + "\n" + "Der Server konnte nicht gefunden werden!");
Thread.Sleep(1000);
Start();
}
Thread t = new Thread(Data_IN);
t.Start();
}
void Data_IN()
{
byte[] buffer;
int readBytes;
for (;;)
{
buffer = new byte[master.SendBufferSize];
readBytes = master.Receive(buffer);
if (readBytes > 0)
{
DataManager(new Packet(buffer));
}
}
}
static List<String> packetsReceived = new List<string>();
static TippForm tippFormCache;
void DataManager(Packet p)
{
PacketType type = p.packetType;
switch (type)
{
case PacketType.Registration:
id = p.gData[0];
Packet rp = new Packet(PacketType.RegisterName, id);
rp.gData.Add(username);
master.Send(rp.ToBytes());
break;
case PacketType.Window:
String windowID = p.gData[0];
if (windowID == ABCDForm.SERIALAZIE_ID)
{
if (p.senderID == "server")
{
if (!packetsReceived.Contains(p.packetID))
{
ABCDForm form = new ABCDForm(id, p.gData[1], p.gData[2], p.gData[3], p.gData[4], p.gData[5]);
if (!IsOpened(form))
{
form.ShowDialog();
packetsReceived.Add(p.packetID);
}
}
}
}
else if (windowID == OpenAnswerForm.SERIALIZE_ID)
{
if (p.senderID == "server")
{
if (!packetsReceived.Contains(p.packetID))
{
OpenAnswerForm form = new OpenAnswerForm(id, p.gData[1]);
if (!IsOpened(form))
{
form.ShowDialog();
packetsReceived.Add(p.packetID);
}
}
}
}
else if (windowID == TippForm.SERIALIZE_ID)
{
if (p.senderID == "server")
{
if (!packetsReceived.Contains(p.packetID))
{
tippFormCache = new TippForm(id, p.gData[1], p.gData[2], p.gData[3], p.gData[4], p.gData[5]);
if (!IsOpened(tippFormCache))
{
tippFormCache.ShowDialog();
packetsReceived.Add(p.packetID);
}
}
}
}
else if (windowID == SoundForm.SERIALAZIE_ID)
{
if (p.senderID == "server")
{
if (!packetsReceived.Contains(p.packetID))
{
SoundForm form = new SoundForm(id, p.gData[1]);
if (!IsOpened(form))
{
form.ShowDialog();
packetsReceived.Add(p.packetID);
}
}
}
}
else if (windowID == VideoPlayerForm.SERIALIZE_ID)
{
if (p.senderID == "server")
{
if (!packetsReceived.Contains(p.packetID))
{
playerForm = new VideoPlayerForm(id);
if (!IsOpened(playerForm))
{
Thread t = new Thread(() => OpenVideoPlayerWithSTA(p));
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
}
}
}
break;
case PacketType.OpenNewTipp:
if(tippFormCache != null)
{
tippFormCache.OpenNewTipp();
}
break;
case PacketType.CanDownload:
if(p.senderID == "server")
{
Uri downloadLink = new Uri(p.gData[0]);
String uri = FileTransfer.DownloadFile(downloadLink);
Packet replyPacket = new Packet(PacketType.HasDownloaded, id);
replyPacket.gData.Add(uri);
master.Send(replyPacket.ToBytes());
}
break;
case PacketType.Play:
if (IsOpened(playerForm))
{
playerForm.Start();
}
break;
case PacketType.TogglePause:
if (IsOpened(playerForm))
{
playerForm.Pause();
}
break;
case PacketType.Stop:
if (IsOpened(playerForm))
{
playerForm.Stop();
}
break;
}
}
private static void OpenVideoPlayerWithSTA(Packet p)
{
playerForm.ShowDialog();
packetsReceived.Add(p.packetID);
}
private static VideoPlayerForm playerForm;
private static bool IsOpened(Form form)
{
FormCollection fc = Application.OpenForms;
foreach(Form f in fc)
{
if(f == form)
{
return true;
}
}
return false;
}
And my Packet Class / Server Data:
[Serializable]
public class Packet
{
public List<String> gData;
public int packetInt;
public bool packetBool;
public string senderID;
public PacketType packetType;
public string packetID;
public Packet(PacketType packetType, string senderID)
{
gData = new List<String>();
this.senderID = senderID;
this.packetType = packetType;
packetID = Guid.NewGuid().ToString();
}
public Packet(byte[] bytes)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream(bytes);
ms.Position = 0;
Packet p = (Packet)bf.Deserialize(ms);
ms.Close();
gData = p.gData;
packetBool = p.packetBool;
packetInt = p.packetInt;
packetType = p.packetType;
senderID = p.senderID;
packetID = Guid.NewGuid().ToString();
}
public byte[] ToBytes()
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
ms.Position = 0;
bf.Serialize(ms, this);
byte[] bytes = ms.ToArray();
ms.Close();
return bytes;
}
public static string GetIP4Address()
{
IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
foreach(IPAddress ip in ips)
{
if(ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "127.0.0.1";
}
}
public enum PacketType
{
Registration,
Window,
/*[0] = FormID
*
* ABCD:
* [1] = Frage
* [2] = A
* [3] = B
* [4] = C
* [5] = D
*
* OPEN:
* [1] = Frage
*
* TIPP:
* [1] = 1. Tipp
* [2] = 2. Tipp
* [3] = 3. Tipp
* [4] = 4. Tipp
* [5] = 5. Tipp
*
* SOUND:
* [1] = Uri
*/
Answer,//[0] = Antwort
OutWindow,
RegisterName,
Play,
TogglePause,
Stop,
OpenNewTipp,
CanDownload,
HasDownloaded
}
I hope you can help me guys.
You activate port forwarding in the router/NAT that connects you to the Internet. Then your friends'clients should have your public IP address (the one of the router to the Internet Provider, you can see this address logging into the router/NAT) and should send the messages to a specific port. You go to the router and configure port forwarding. This assuming local network means your network is behind a router that connects you to the Internet.

Asynchronous socket + waitone()

Let's start with some code:
class InternetConnector
{
private struct ConnectionData
{
public Action<Socket> SuccessHandler { get; set; }
public ClientStateObject clientObj { get; set; }
public Action<Exception> ErrorHandler { get; set; }
public Socket Socket { get; set; }
}
public static ManualResetEvent processingDone = new ManualResetEvent( false );
public static ConcurrentQueue<string> messages = new ConcurrentQueue<string>();
public bool ReceiveMessage(Action<Socket> successHandler, Action<Exception> errorHandler)
{
ClientStateObject obj = new ClientStateObject();
obj.server = client;
var connectionData = new ConnectionData
{
ErrorHandler = errorHandler,
SuccessHandler = successHandler,
Socket = client,
clientObj = obj
};
if (Connected)
{
client.BeginReceive(connectionData.clientObj.buffer, 0, ClientStateObject.bufSize, 0, new AsyncCallback(ReceiveCallback), connectionData);
receive = true;
receiveDone.WaitOne();
}
return receive;
}
private static void ReceiveCallback(IAsyncResult ar)
{
ConnectionData connectionData = new ConnectionData();
bool complete = false;
try
{
connectionData = (ConnectionData)ar.AsyncState;
Socket client = connectionData.Socket;
int num = client.EndReceive(ar);
{
connectionData.clientObj.stringBuffer.Append(Encoding.ASCII.GetString(connectionData.clientObj.buffer, 0, num));
string response = connectionData.clientObj.stringBuffer.ToString();
string[] msgs = response.Split('&');
for (int i = 0; i < msgs.Count(); i++)
{
string sts = msgs[i];
messages.Enqueue(sts + "&" );
}
receiveDone.Set();
if (connectionData.SuccessHandler != null)
{
connectionData.SuccessHandler(client);
processingDone.WaitOne();
client.BeginReceive(connectionData.clientObj.buffer, 0, ClientStateObject.bufSize, 0, new AsyncCallback(ReceiveCallback), connectionData);
}
}
}
catch (Exception e)
{
if (connectionData.ErrorHandler != null)
connectionData.ErrorHandler(e);
}
}
public partial class Form1 : Form
{
private InternetConnector client = new InternetConnector();
private bool isRunning = false;
private void AsyncSuccessHandler(Socket socket)
{
if (InvokeRequired)
{
BeginInvoke(new Action( () => AsyncSuccessHandler( socket ) ));
return;
}
if (InternetConnector.messages.Count() == 0)
{
status.Text = "Signals Receiver: Connected";
status.ForeColor = Color.Green;
isRunning = true;
client.ReceiveMessage(AsyncSuccessHandler, AsyncErrorHandler);
}
else
{
GUIChangeOnConnection();
InternetConnector.processingDone.Set();
}
}
private void GUIChangeOnConnection()
{
for( int i = 0; i < InternetConnector.messages.Count; i++ )
{
string message;
InternetConnector.messages.TryDequeue( out message );
// process the message
}
}
}
Now the problem.
Everything works fine. Reading from the socket is happening. However the call processingDone.WaitOne(); which should block the callback indefinitely until the call to processingDone.Set(); returns too early.
I verified it by setting the breakpoint at the end of the GUIChangeOnConnection(); - function closing bracket line. It hits the breakpoint and looking at the InternetConnector.messages I see that the queue is not empty, which means that the for loop did not finish.
And the second time this breakpoint is hit the number of messages in the queue is sky-rocketing.
What am I doing wrong? Or maybe my design is incorrect?
Thank you.

Waiting for event to finish

Im trying to convert the response from the webclient to Json, but it's trying to create the JSON object before it is done downloaing it from the server.
Is there a "nice" way to for me to wait for WebOpenReadCompleted to be executed?
Have to mention that this is a WP7 app, so everything is Async
public class Client
{
public String _url;
private String _response;
private WebClient _web;
private JObject jsonsobject;
private Boolean blockingCall;
private Client(String url)
{
_web = new WebClient();
_url = url;
}
public JObject Login(String username, String password)
{
String uriUsername = HttpUtility.UrlEncode(username);
String uriPassword = HttpUtility.UrlEncode(password);
Connect(_url + "/data.php?req=Login&username=" + uriUsername + "&password=" + uriPassword + "");
jsonsobject = new JObject(_response);
return jsonsobject;
}
public JObject GetUserInfo()
{
Connect(_url + "/data.php?req=GetUserInfo");
jsonsobject = new JObject(_response);
return jsonsobject;
}
public JObject Logout()
{
Connect(_url + "/data.php?req=Logout");
jsonsobject = new JObject(_response);
return jsonsobject;
}
private void Connect(String url)
{
_web.Headers["Accept"] = "application/json";
_web.OpenReadCompleted += new OpenReadCompletedEventHandler(WebOpenReadCompleted);
_web.OpenReadAsync(new Uri(url));
}
private void WebOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null || e.Cancelled)
{
MessageBox.Show("Error:" + e.Error.Message);
_response = "";
}
else
{
using (var reader = new StreamReader(e.Result))
{
_response = reader.ReadToEnd();
}
}
}
}
You can use an EventWaitHandle to nicely block until the async read is complete. I had a similar requirement for downloading files with WebClient. My solution was to subclass WebClient. Full source is below. Specifically, DownloadFileWithEvents blocks nicely until the async download completes.
It should be pretty straightforward to modify the class for your purpose.
public class MyWebClient : WebClient, IDisposable
{
public int Timeout { get; set; }
public int TimeUntilFirstByte { get; set; }
public int TimeBetweenProgressChanges { get; set; }
public long PreviousBytesReceived { get; private set; }
public long BytesNotNotified { get; private set; }
public string Error { get; private set; }
public bool HasError { get { return Error != null; } }
private bool firstByteReceived = false;
private bool success = true;
private bool cancelDueToError = false;
private EventWaitHandle asyncWait = new ManualResetEvent(false);
private Timer abortTimer = null;
const long ONE_MB = 1024 * 1024;
public delegate void PerMbHandler(long totalMb);
public event PerMbHandler NotifyMegabyteIncrement;
public MyWebClient(int timeout = 60000, int timeUntilFirstByte = 30000, int timeBetweenProgressChanges = 15000)
{
this.Timeout = timeout;
this.TimeUntilFirstByte = timeUntilFirstByte;
this.TimeBetweenProgressChanges = timeBetweenProgressChanges;
this.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(MyWebClient_DownloadFileCompleted);
this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(MyWebClient_DownloadProgressChanged);
abortTimer = new Timer(AbortDownload, null, TimeUntilFirstByte, System.Threading.Timeout.Infinite);
}
protected void OnNotifyMegabyteIncrement(long totalMb)
{
if (NotifyMegabyteIncrement != null) NotifyMegabyteIncrement(totalMb);
}
void AbortDownload(object state)
{
cancelDueToError = true;
this.CancelAsync();
success = false;
Error = firstByteReceived ? "Download aborted due to >" + TimeBetweenProgressChanges + "ms between progress change updates." : "No data was received in " + TimeUntilFirstByte + "ms";
asyncWait.Set();
}
void MyWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
if (cancelDueToError) return;
long additionalBytesReceived = e.BytesReceived - PreviousBytesReceived;
PreviousBytesReceived = e.BytesReceived;
BytesNotNotified += additionalBytesReceived;
if (BytesNotNotified > ONE_MB)
{
OnNotifyMegabyteIncrement(e.BytesReceived);
BytesNotNotified = 0;
}
firstByteReceived = true;
abortTimer.Change(TimeBetweenProgressChanges, System.Threading.Timeout.Infinite);
}
public bool DownloadFileWithEvents(string url, string outputPath)
{
asyncWait.Reset();
Uri uri = new Uri(url);
this.DownloadFileAsync(uri, outputPath);
asyncWait.WaitOne();
return success;
}
void MyWebClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (cancelDueToError) return;
asyncWait.Set();
}
protected override WebRequest GetWebRequest(Uri address)
{
var result = base.GetWebRequest(address);
result.Timeout = this.Timeout;
return result;
}
void IDisposable.Dispose()
{
if (asyncWait != null) asyncWait.Dispose();
if (abortTimer != null) abortTimer.Dispose();
base.Dispose();
}
}
I see you are using OpenReadAsync(). This is an asynchronous method, meaning that the calling thread is not suspended while the handler is executing.
This means your assignment operation setting jsonsobject happens while WebOpenReadCompleted() is still executing.
I'd say your best bet is to replace OpenReadAsync(new Uri(url)) with OpenRead(new Uri(url)) in your Connect(string url) method.
OpenRead() is a synchronous operation, so the calling method will wait until the WebOpenReadCompleted() method is complete before your assignment occurs in the Connect() method.

Categories

Resources