I want to connect to a server using Ip address from client. To get the Ip address of server I am using below code, It detecting the server correctly but I want to perform some other function after HostEndPoint variable set by event handler untill that I need to make wait How can I implement it? .. Below code used to scan is Proper way? If not how?
Thanks
int startIp = 0;
int EndIp = 255;
int HostPort = 4678;
string = ipPrefix = "192.168.1.";
EndPoint HostEndPoint;
private void ScanHosts()
{
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
for (startIP = 0; startIP <= endIP; startIP++)
{
DnsEndPoint endPoint = new DnsEndPoint(ipPrefix + startIP.ToString(), HostPort);
try
{
SocketAsyncEventArgs socketEventArgs = new SocketAsyncEventArgs();
socketEventArgs.RemoteEndPoint = endPoint;
socketEventArgs.UserToken = clientSocket;
socketEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketEventArgs_Connected);
clientSocket.ConnectAsync(socketEventArgs);
}
catch { }
}
}
private void socketEventArgs_Connected(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
HostEndPoint = e.RemoteEndPoint;
}
}
You can use AutoResetEvent for it. FE my usage:
AutoResetEvent autoResetLoadDiscTitleAndPersonalDataById = new AutoResetEvent(false);
DataService.LoadDiscTitleAndPersonalDataById(titleToSync.id_on_server, titleInfoXML =>
{
Title TitleInfo = new Title(titleInfoXML);
TitleInfo.UpdateToDb();
autoResetLoadDiscTitleAndPersonalDataById.Set();
});
autoResetLoadDiscTitleAndPersonalDataById.WaitOne();
Related
I'm changing some old sync/threaded code to async,
basically im implementing a 'server emulator' for an old flash game,
and trying to make the packet reading async to hopefully speed things up a little.
private List<byte> currentPacket = new List<byte>();
private byte[] workBuffer = new byte[1028];
private bool dcLock = false;
public GameClient(Socket clientSocket)
{
ClientSocket = clientSocket;
RemoteIp = clientSocket.RemoteEndPoint.ToString();
if (RemoteIp.Contains(":"))
RemoteIp = RemoteIp.Substring(0, RemoteIp.IndexOf(":"));
Logger.DebugPrint("Client connected # " + RemoteIp);
kickTimer = new Timer(new TimerCallback(kickTimerTick), null, kickInterval, kickInterval);
warnTimer = new Timer(new TimerCallback(warnTimerTick), null, warnInterval, warnInterval);
minuteTimer = new Timer(new TimerCallback(minuteTimerTick), null, oneMinute, oneMinute);
connectedClients.Add(this);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += receivePackets;
e.SetBuffer(workBuffer, 0, workBuffer.Length);
ClientSocket.ReceiveAsync(e);
}
public static void CreateClient(object sender, SocketAsyncEventArgs e)
{
Socket eSocket = e.AcceptSocket;
e.AcceptSocket = null;
socket.AcceptAsync(e);
GameClient client = new GameClient(eSocket);
}
private void receivePackets(object sender, SocketAsyncEventArgs e)
{
// HI1 Packets are terminates by 0x00 so we have to read until we receive that terminator
if (e.SocketError == SocketError.Success && !isDisconnecting)
{
int availble = e.BytesTransferred;
if (availble >= 1)
{
for (int i = 0; i < availble; i++)
{
currentPacket.Add(e.Buffer[i]);
if (e.Buffer[i] == PacketBuilder.PACKET_TERMINATOR)
{
parsePackets(currentPacket.ToArray());
currentPacket.Clear();
}
}
}
Array.Clear(e.Buffer);
ClientSocket.ReceiveAsync(e);
return;
}
else
{
Disconnect();
}
while (dcLock) { }; // Refuse to shut down until dcLock is cleared. (prevents TOCTOU issues.)
// Stop Timers
if (inactivityTimer != null)
inactivityTimer.Dispose();
if (warnTimer != null)
warnTimer.Dispose();
if (kickTimer != null)
kickTimer.Dispose();
// Call OnDisconnect
connectedClients.Remove(this);
GameServer.OnDisconnect(this);
LoggedIn = false;
// Close Socket
ClientSocket.Close();
ClientSocket.Dispose();
return;
}
now you see
e.Completed += receivePackets;
e.SetBuffer(workBuffer, 0, workBuffer.Length);
ClientSocket.ReceiveAsync(e);
for some reason receivePackets is never being called,
if i open up NetCat and connect to 127.0.0.1:12321 and send stuff there it works,
but from in the original flash-based client of the game? nothing happens.
no call to receivePackets ever happens, even if the buffer is only 1 byte.
even after disconnecting the client...
but it worked in my sync implementation where i just called clientSocket.Receive() in a loop.. so why doesnt it work now in async verison?
I have this code on my server side.
public static void Data_IN(object cSocket)
{
Socket clientSocket = (Socket)cSocket;
byte[] Buffer;
int readBytes;
while (true)
{
Buffer = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(Buffer);
if (readBytes > 0)
{
Packet p = new Packet(Buffer);
DataManager(p);
}
}
}
And the main problem is that when I stop debugging the code the server always crashes and says
System.Net.Sockets.SocketException: the remote server closed connection
The error is always at readBytes = clientSocket.Recieve(Buffer);
That is the only way I can crash the server, my only concern is when someone uses the chat program that I have created and his/hers computer crashes the chat server will go down and I always need to restart the server.
Clientside code below which executes when closing the window
private void MainWindow_Closed(object sender, EventArgs e)
{
if (isConnected)
{
Packet p = new Packet(PacketType.CloseConnection, ID);
p.data.Add(login);
p.data.Add("exits from chat");
socket.Send(p.ToBytes());
socket.Close();
isConnected = false;
thread.Abort();
}
}
On below there is the code part which uses data_in, that code is on the client side
private void ConnectBtn_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(Login.Text))
{
MessageBox.Show("Add username");
}
else if (!IPAddress.TryParse(serverIP.Text, out ipAdress))
{
MessageBox.Show("Add valid ip");
}
else
{
ClearRequireMsg();
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 4242);
try
{
socket.Connect(ipEndPoint);
login = Login.Text;
isConnected = true;
ConnectBtn.IsEnabled = false;
SendBtn.IsEnabled = true;
thread = new Thread(Data_IN);
thread.Start();
}
catch (SocketException ex)
{
AddMsgToBoard("Error during connecting to server", "System");
}
}
}
You're calling the function Data_IN without passing any parameter.
thread = new Thread(Data_IN);
Right way:
new Thread(() => Data_IN(socket));
Im implementing a WebService with TCP. The webservice is the Server side that accept multiple clients. Is there any suggestions on how to configure a default port where to start the tcp clients? And with every client connected (aprox. 10 clients) will have an assigned port.
(I'm using Visual Studio 2010 the language is c#, Here is a code block for accepting the clients.)
Any suggestions will be accepted. Thanks!
private void StartListening(object sender, EventArgs e)
{
try
{
//Will move one the array of threads
index++;
//Will get the current IP Address
IPAddress ipaddr = IPAddress.Any;
//Port where the data will pass.
//First Port in use. 10,000
int Port = 10000;
if (true)
{
_TCPListener = new TcpListener(ipaddr, Port);
Port = Port + 1;
//Start Listening
_TCPListener.Start();
ThreadStart.Add(new ThreadStart(() => _TCPListener.BeginAcceptTcpClient(CompleteAcceptClient, _TCPListener)));
Thread.Add(new Thread(ThreadStart[index]));
Thread[index].Start();
}
else
{
_TCPListener = new TcpListener(ipaddr, Port + 2);
_TCPListener.Start();
ThreadStart delegateT = new ThreadStart(() => _TCPListener.BeginAcceptTcpClient(CompleteAcceptClient, _TCPListener));
Thread T = new Thread(delegateT);
T.Start();
}
}
catch(Exception ex)
{
throw ex;
}
}
//Here is the accept client method.
private void CompleteAcceptClient(IAsyncResult iar)
{
TcpListener tcpl = (TcpListener)iar.AsyncState;
try
{
ThreadStart delegateR = new ThreadStart(() => _TCPClient = tcpl.EndAcceptTcpClient(iar));
Thread R = new Thread(delegateR);
R.Start();
mRx = new byte[1024];
_TCPClient.GetStream().BeginRead(mRx, 0, mRx.Length, onCompleteReadFromTCPClientStream, _TCPClient);
}
catch(Exception e)
{
throw e;
}
}
This is the first time I have used Windows Form application to do a socket server / client.
I have ran into a problem with my Socket.bind(IPEndpoint) under my public void Listen(). I get the error
Only one usage of each socket address (protocol/network address/port) is normally permitted
Any ideas how I could go about fixing this?
public Form1()
{
CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
}
Socket sck;
Socket acc;
IPEndPoint ipe;
List<Socket> lstClient = new List<Socket>();
Thread handleClient;
string myIP = "";
public void IP()
{
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress address in host.AddressList)
{
if (address.AddressFamily.ToString() == "InterNetwork")
{
myIP = address.ToString();
}
}
ipe = new IPEndPoint(IPAddress.Parse(myIP), 2001);
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.IP);
}
private void btnListen_Click(object sender, EventArgs e)
{
this.Form1_Load(sender, e);
}
private void rtbMain_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
IP();
handleClient = new Thread(new ThreadStart(Listen));
handleClient.IsBackground = true;
handleClient.Start();
}
public void Listen()
{
sck.Bind(ipe);
sck.Listen(3);
while(true)
{
Socket acc=sck.Accept();
lstClient.Add(acc);
Thread clientProcess = new Thread(myThreadClient);
clientProcess.IsBackground = true;
clientProcess.Start(acc);
rtbMain.SelectionFont = new Font("Arial", 18, FontStyle.Bold);
rtbMain.SelectionColor = Color.Green;
rtbMain.AppendText("accept connections from" +
acc.RemoteEndPoint.ToString());
rtbMain.ScrollToCaret();
}
}
private void myThreadClient(object obj)
{
Socket clientACC = (Socket)obj;
while(true)
{
byte[] sizeBuf = new byte[1024];
int rec = clientACC.Receive(sizeBuf);
foreach (Socket acc in lstClient)
{
acc.Send(sizeBuf,sizeBuf.Length,SocketFlags.None);
}
}
}
This could happen if a socket is already listening in same port in your application any other process.
Just make sure no apps us it, and make sure you don't run multiple instances of your same application(verify it with taskmanager).
Aside:
Never use CheckForIllegalCrossThreadCalls = false
Have meaningful method names.
Your IP method doesn't makes sense to name it as IP. I'd rather name it as GetIPAndCreateSocket or something like that.
Method name should tell us what that method is going to do.
How do I get all servers IP which are listening on specific port (Ex:9090) in LAN
I have already read some basics information about multicast,anycast ,unicast and broadcast and it seems like broadcast is the one meant for my application.
I am thinking of two ideas .. Use TCP protocol to Connect to all IP Addresses (192.168.1.1-254) in parallel on port 9090 and set a little time period to the connection timeout. just to check if there's any responce. (but it doesn't seem like a good idea)Use UDP protocol and broadcast a message like "hello" and check for response then get all IP Addresses which respond.
So which idea should I pick, are there better ideas to do it?
I would also like to know if my broadcast-ed message is received to the server and how to get the IP address of it.
I've done it with TCP to search all server that is listening on a specific port.
Its not an idle solution, but it worked for me.
I've created a userControl with a public function Initialize to pass the port that i want to scan for servers.
public ServerDiscovery()
{
InitializeComponent();
// statusLabel.Image = imageState.Images[2];
timer.Elapsed += timer_tick;
}
int port = 0;
bool busy = false; // to tell that the function is busy with scanning.
public void Initialize(int port)
{
this.port = port;
}
System.Timers.Timer timer = new System.Timers.Timer(5000);
List<SocketAsyncEventArgs> list = new List<SocketAsyncEventArgs>();
// this list to hold all sockets that created to connect to IP .. to DISPOSE it later
HashSet<string> usedIP = new HashSet<string>();
//usedIP will be explained later.
public IPEndPoint getAddress()
{ //this function to get the IPEndPoint of the selected server from listview.
if (listServer.SelectedItems.Count > 0)
{
if (listServer.SelectedItems[0].ImageIndex == 0)
{
ListViewItem item = listServer.SelectedItems[0];
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(item.SubItems[1].Text), port);
return ep;
}
}
return null;
}
public void Refresh() //to scan for servers
{
if (!busy)
{
usedIP.Clear();
listServer.Items.Clear();
// statusLabel.Text = "Scanning for servers.";
// statusLabel.Image = Image.FromFile("loading.gif");
// btnRefresh.Enabled = false;
busy = true;
timer.Start();
IPAddress[] IpA = Dns.GetHostByName(Dns.GetHostName()).AddressList;
for (int j = 0; j < IpA.Length ; j++)
{
if (IpA[j].AddressFamily == AddressFamily.InterNetwork) // to make sure it's an IPV4
{
string scanIP = IpA[j].ToString().Substring(0, IpA[j].ToString().LastIndexOf(".")) + ".";
if (!usedIP.Contains(scanIP))
//usedIP is a hashset that holds the first 3 parts on an ip (ex:"192.168.1." from "192.168.1.30") i used this to avoid scanning the same ip addresses more than once .. like if i had a wireless network ip ("192.168.1.5") and an Ethernet Network ip ("192.168.1.5"). so with that hashset it will scan once.
{
usedIP.Add(scanIP);
Parallel.For(1, 255, i =>
{
Scan(scanIP + i);
});
}
}
}
}
}
private void Scan(string ipAdd)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ipAdd), port);
e.UserToken = s;
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
list.Add(e); // add the created socket to a list to dispose when time is up.
s.ConnectAsync(e);
}
private void e_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.ConnectSocket != null) //if there's a responce from the server [e.ConnectSocket] will not be equal null.
{
StreamReader sr = new StreamReader(new NetworkStream(e.ConnectSocket));
ListViewItem item = new ListViewItem();
string[] cmd = sr.ReadLine().Split('<'); in my server constructor this line will receive a string like "PC_NAME<Available" ..
item.Text = cmd[0];
item.SubItems.Add(((IPEndPoint)e.RemoteEndPoint).Address.ToString());
item.SubItems.Add(cmd[1]);
if (cmd[1] == "Busy")
item.ImageIndex = 1;
else
item.ImageIndex = 0;
AddServer(item);
list.Remove(e); //active server should be remove from the list that holds the sockets and disposed.. because there's no need to keep connection after showing that this server is active.
((Socket)e.UserToken).Dispose();
}
}
delegate void AddItem(ListViewItem item);
private void AddServer(ListViewItem item)
{
if (InvokeRequired)
{
Invoke(new AddItem(AddServer), item); //just to add an item from a background thread.
return;
}
listServer.Items.Add(item);
}
private void timer_tick(object sender, EventArgs e)
{
busy = false; //when time's up .. set busy to false so we can scan again
timer.Stop();
foreach (var s in list) //dispose all sockets that's trying to connect and waiting for a response
{
try
{
((Socket)s.UserToken).Dispose();
}
catch { }
}
//this.Invoke((MethodInvoker)delegate // for design
// {
// btnRefresh.Enabled = true;
// btnRefresh.BorderStyle = Border3DStyle.Raised;
// statusLabel.Text = "Ready.";
// statusLabel.Image = imageState.Images[2];
// });
}
private void btnRefresh_Click(object sender, EventArgs e)
{
// btnRefresh.BorderStyle = Border3DStyle.Sunken;
Refresh();
}
// private void listServer_KeyUp(object sender, KeyEventArgs e)
// {
// if (e.KeyCode == Keys.F5)
// {
// btnRefresh_Click(sender, (EventArgs)e);
// }
// }
}
Again this's not an ideal solution that works on any case but it worked fine with me.