I am trying to make a program in witch multiply clients will connect to the server. But i have a problem because when i try to connect more than 1 client at the same time, it takes a "long time" to do it.
i am using asynchronous way to connect:
public bool connect(string IP,int port)
{
try
{
if (m_clientSocket == null)
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(IP.ToString());
int iPortNo = System.Convert.ToInt16(port.ToString());
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
}
}catch()
{
return false;
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (m_clientSocket != null)
{
if (m_clientSocket.Connected)
{
client.EndConnect(ar);
// send next data here
}
else
{
client.EndConnect(ar);
m_clientSocket.Close();
m_clientSocket = null;
state = CONNECT_ERROR;
}
}
}
catch ()
{
}
}
For each client I want to connect I open a new class that includes two methods that you can see above. than with simple for loop I call methods one after another.
in Wireshark I observe the time that next needs to connect to a server is 0.1s witch I think is allot.
Any idea why does it take so long ?
Thanks for any kind of help.
Related
I have previously had this code working, and am unsure of the cause of the issue i am currently having. I am writing a simple client/server application for encrypted chat. The server allows for multiple simultaneous clients. When i bind the server to the local IP Address i can connect with multiple local clients simultaneously, but when I bind it to the external IP address, only the first instance on the local machine will connect, but other devices may connect with multiple instances simultaneously. In this case even closing the first instance will not allow another to connect, and the AcceptCallBack is never called. I have been unable to find any other reports of this issue. Reasons that come to mind include that I made some sort of mistake in the code, or I need to separately listen for local connections and remote connections, or that it is a router/firewall issue.
For my server i have:
public partial class frmServer : Form
{
Thread listenThread;
private static bool listening = false;
private static List<StateObject> Users = new List<StateObject>();
public frmServer()
{
InitializeComponent();
}
private void frmServer_Load(object sender, EventArgs e)
{
listenThread = new Thread(new ThreadStart(StartListening));
listenThread.Start();
}
public static void StartListening()
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 19541);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
listening = true;
while (true)
{
//check if there are new connections
if (!listening)
{
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
listening = true;
}
Thread.Sleep(50);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
listening = false;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
Users.Add(state);
}
}
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
//user info
}
And For the client i have
public partial class frmClient : Form
{
public frmClient()
{
InitializeComponent();
}
private void frmClient_Load(object sender, EventArgs e)
{
StartClient();
}
private void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
IPHostEntry ipHostInfo = Dns.GetHostEntry("Remote Host Address");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP V4 socket.
Socket client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
The requirement is server socket should accept the client socket connection all the time (windows service application). Below is the code which works fine for several hours, but after sometime accept does not work at all. To keep the accept all the time, I also have thread which connects the server every 10 min. By this way I got to know that server socket has stopped after some time (several hours)
public void StartReceiveNotification()
{
if (!isStarted)
{
try
{
byte[] bytes = new Byte[1024];
var ips = Dns.GetHostAddresses(Dns.GetHostName());
var myAddress = ips.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
assigningIp = myAddress;
server = new TcpListener(myAddress, 11001);
server.Start();
AcceptSockets();
isStarted = true;
}
catch (Exception ex)
{
logger.Error(ex);
}
}
}
private void AcceptSockets()
{
try
{
while (true)
{
var acceptedSocket = server.AcceptSocket();
var state = new StateObject { BufferSize = 6000, Socket = acceptedSocket };
acceptedSocket.BeginReceive(state.Buffer, 0, state.BufferSize, 0, this.ReadCallback, state);
acceptedSockets.Add(acceptedSocket);
}
}
catch (Exception ex)
{
logger.Error(ex);// no exception but stops accepting socket
}
}
internal ElapsedEventHandler SendKeepLiveCommand()// triggers every 10 min
{
try
{
if (assigningIp != null)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(assigningIp, 11001);
socket.Send(ASCIIEncoding.ASCII.GetBytes("keepAlive"));
socket.Disconnect(false);
socket.Dispose();
}
}
catch (Exception ex)
{
logger.Error(ex);// get exception after several hours
}
return null;
}
issue was server had vpn connection and it was using that ip address. when vpn connection lost server stopped listening.
I want to use a C# plugin in my Unity project. That plugin should act as a server which will get values from a client so that I'd be able to use those values for further processing.
The issue is that the server has infinite loop. And infinite loops cause Unity to hang. How to handle this?
EDIT: I'm attaching a code snippet of server program. In my opinion, there are 2 points which may be causing problem. The infinite loops and the point where program is suspended as commented in code:
void networkCode()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 1755);
// Create a TCP/IP socket.
listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true)
{
// Program is suspended while waiting for an incoming connection.
Debug.Log("HELLO"); //It works
handler = listener.Accept();
Debug.Log("HELLO"); //It doesn't work
data = null;
// An incoming connection needs to be processed.
while (true)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
{
break;
}
System.Threading.Thread.Sleep(1);
}
System.Threading.Thread.Sleep(1);
}
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
EDIT: After help from #Programmer, the C# plugin is complete. But Unity is not reading the correct values. I'm attaching the Unity side code:
using UnityEngine;
using System;
using SyncServerDLL; //That's our library
public class receiver : MonoBehaviour {
SynchronousSocketListener obj; //That's object to call server methods
// Use this for initialization
void Start() {
obj = new SynchronousSocketListener ();
obj.startServer ();
}
// Update is called once per frame
void Update() {
Debug.Log (obj.data);
}
}
I have tested SynchronousSocketListener class thoroughly in Visual Studio. It is giving good results there.
Use Thread to do your server Listen and read and write actions.
You can declare socket and other networkstream objects as public then initialize them in a thread function.
Unity does not work well with while loops in Threads and may freeze sometimes, but you can fix that by adding System.Threading.Thread.Sleep(1); in your while loop where you are reading or waiting for data to arrive from socket.
Make sure to stop the Thread in OnDisable() function. Do NOT access Unity API from the new Thread function. Just do only the socket stuff there and return the data to a public variable.
System.Threading.Thread SocketThread;
volatile bool keepReading = false;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
startServer();
}
void startServer()
{
SocketThread = new System.Threading.Thread(networkCode);
SocketThread.IsBackground = true;
SocketThread.Start();
}
private string getIPAddress()
{
IPHostEntry host;
string localIP = "";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
}
}
return localIP;
}
Socket listener;
Socket handler;
void networkCode()
{
string data;
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// host running the application.
Debug.Log("Ip " + getIPAddress().ToString());
IPAddress[] ipArray = Dns.GetHostAddresses(getIPAddress());
IPEndPoint localEndPoint = new IPEndPoint(ipArray[0], 1755);
// Create a TCP/IP socket.
listener = new Socket(ipArray[0].AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true)
{
keepReading = true;
// Program is suspended while waiting for an incoming connection.
Debug.Log("Waiting for Connection"); //It works
handler = listener.Accept();
Debug.Log("Client Connected"); //It doesn't work
data = null;
// An incoming connection needs to be processed.
while (keepReading)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
Debug.Log("Received from Server");
if (bytesRec <= 0)
{
keepReading = false;
handler.Disconnect(true);
break;
}
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
{
break;
}
System.Threading.Thread.Sleep(1);
}
System.Threading.Thread.Sleep(1);
}
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
void stopServer()
{
keepReading = false;
//stop thread
if (SocketThread != null)
{
SocketThread.Abort();
}
if (handler != null && handler.Connected)
{
handler.Disconnect(false);
Debug.Log("Disconnected!");
}
}
void OnDisable()
{
stopServer();
}
tried to solve this alone for the past I don't even know but no googling will help me here, I would need some advice with this one. I am receiving UDP packets from another PC on my local network every 10 seconds, can see them in wireshark but the application is stuck on the udpClient.Receive() line. The multicast group and port are the right values, checked in main() n+1 times. Please suggest a solution if you have any idea that might help. Thanks.
(I'm trying to receive the server's information so that th application can automaticaly start to communicate vith it via TCP)
class MulticastListener {
private UdpClient udpClient;
private IPEndPoint remoteEndPoint;
IPAddress multicastIP;
private int port;
public MulticastListener(ref IPAddress multicastIP, int port) {
remoteEndPoint = new IPEndPoint(IPAddress.Any, port);
this.multicastIP = multicastIP;
this.port = port;
udpClient = new UdpClient();
udpClient.Client.Bind(remoteEndPoint);
}
public IPEndPoint GetServer() {
try {
udpClient.JoinMulticastGroup(multicastIP);
} catch (ObjectDisposedException e) {
Console.WriteLine("ERROR: The underlying socket has been closed!");
} catch (SocketException e) {
Console.WriteLine("ERROR: An error occurred when accessing the socket!");
} catch (ArgumentException e) {
Console.WriteLine("ERROR: The IP address is not compatible with the AddressFamily value that defines the addressing scheme of the socket!");
}
Byte[] serverInfoBytes = udpClient.Receive(ref remoteEndPoint);
Stream stream = new MemoryStream(serverInfoBytes); //receives a serialised IPEndpoint object
BinaryFormatter formatter = new BinaryFormatter();
udpClient.Close();
return (IPEndPoint)formatter.Deserialize(stream);
}
}
As I commented, your code works fine for me 100% as is. I would check you are sending on the same subnet you are receiving on. Perhaps your sender is not configured to the right interface?
Perhaps it would help to try out a different sender, here is what I used to test:
static void Main(string[] args)
{
//Configuration
var interfaceIp = IPAddress.Parse("192.168.9.121");
var interfaceEndPoint = new IPEndPoint(interfaceIp, 60001);
var multicastIp = IPAddress.Parse("230.230.230.230");
var multicastEndPoint = new IPEndPoint(multicastIp, 60001);
//initialize the socket
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.ExclusiveAddressUse = false;
socket.MulticastLoopback = false;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
MulticastOption option = new MulticastOption(multicastEndPoint.Address, interfaceIp);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, option);
//bind on a network interface
socket.Bind(interfaceEndPoint);
//initialize args for sending packet on the multicast channel
var sockArgs = new SocketAsyncEventArgs();
sockArgs.RemoteEndPoint = multicastEndPoint;
sockArgs.SetBuffer(new byte[1234], 0, 1234);
//send an empty packet of size 1234 every 3 seconds
while (true)
{
socket.SendToAsync(sockArgs);
Thread.Sleep(3000);
}
}
I have currently-working code which sends raw data to a printer by writing a temporary file, then using File.Copy() to send it to the printer. File.Copy() supports both local ports, like LPT1 and shared printers like \\FRONTCOUNTER\LabelPrinter.
However, now I'm trying to get it working with a printer that's directly on the network: 192.168.2.100, and I can't figure out the format to use.
File.Copy(filename, #"LPT1", true); // Works, on the FRONTCOUNTER computer
File.Copy(filename, #"\\FRONTCOUNTER\LabelPrinter", true); // Works from any computer
File.Copy(filename, #"\\192.168.2.100", true); // New printer, Does not work
I know it's possible to "Add a printer" from each computer, but I'm hoping to avoid that - the second line of code above works from any computer on the network automatically, with no configuration required. I also know it's possible to P/Invoke the windows print spooler, and if that's my only option I may take it, but that's much more code overhead than I'd like to have.
Ideally, someone will have either a way to make File.Copy() work or a similar C# statement which will accept a network IP.
You can use sockets and send the data straight to that IP address. Should pretty much be the same as File.Copy. I just tried it out and that worked.
I just sent some text but here is the code that I used
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.NoDelay = true;
IPAddress ip = IPAddress.Parse("192.168.192.6");
IPEndPoint ipep = new IPEndPoint(ip, 9100);
clientSocket.Connect(ipep);
byte[] fileBytes = File.ReadAllBytes("test.txt");
clientSocket.Send(fileBytes);
clientSocket.Close();
try this code:
public class PrintHelper
{
private readonly IPAddress PrinterIPAddress;
private readonly byte[] FileData;
private readonly int PortNumber;
private ManualResetEvent connectDoneEvent { get; set; }
private ManualResetEvent sendDoneEvent { get; set; }
public PrintHelper(byte[] fileData, string printerIPAddress, int portNumber = 9100)
{
FileData = fileData;
PortNumber = portNumber;
if (!IPAddress.TryParse(printerIPAddress, out PrinterIPAddress))
throw new Exception("Wrong IP Address!");
}
public PrintHelper(byte[] fileData, IPAddress printerIPAddress, int portNumber = 9100)
{
FileData = fileData;
PortNumber = portNumber;
PrinterIPAddress = printerIPAddress;
}
/// <inheritDoc />
public bool PrintData()
{
//this line is Optional for checking before send data
if (!NetworkHelper.CheckIPAddressAndPortNumber(PrinterIPAddress, PortNumber))
return false;
IPEndPoint remoteEP = new IPEndPoint(PrinterIPAddress, PortNumber);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.NoDelay = true;
connectDoneEvent = new ManualResetEvent(false);
sendDoneEvent = new ManualResetEvent(false);
try
{
client.BeginConnect(remoteEP, new AsyncCallback(connectCallback), client);
connectDoneEvent.WaitOne();
client.BeginSend(FileData, 0, FileData.Length, 0, new AsyncCallback(sendCallback), client);
sendDoneEvent.WaitOne();
return true;
}
catch
{
return false;
}
finally
{
// Shutdown the client
this.shutDownClient(client);
}
}
private void connectCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
connectDoneEvent.Set();
}
private void sendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
// Signal that all bytes have been sent.
sendDoneEvent.Set();
}
private void shutDownClient(Socket client)
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
Network Helper class:
public static class NetworkHelper
{
public static bool CheckIPAddressAndPortNumber(IPAddress ipAddress, int portNumber)
{
return PingIPAddress(ipAddress) && CheckPortNumber(ipAddress, portNumber);
}
public static bool PingIPAddress(IPAddress iPAddress)
{
var ping = new Ping();
PingReply pingReply = ping.Send(iPAddress);
if (pingReply.Status == IPStatus.Success)
{
//Server is alive
return true;
}
else
return false;
}
public static bool CheckPortNumber(IPAddress iPAddress, int portNumber)
{
var retVal = false;
try
{
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.Connect(iPAddress, portNumber);
retVal = tcpClient.Connected;
tcpClient.Close();
}
return retVal;
}
catch (Exception)
{
return retVal;
}
}
}