I'm writing a server application and I want to use IOCompletion ports, so I wrote a prototype for the server, but I'm facing a problem with GetQueuedCompletionStatus that it never returns(it blocks). Below is my code:
bool CreateSocketOverlappedServer()
{
WSADATA wsaData;
SOCKADDR_IN sockaddr;
if(WSAStartup(MAKEWORD(2,2,),&wsaData)){
_tprintf(_T("Unable to start up\n"));
return false;
}
SrvSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,NULL,WSA_FLAG_OVERLAPPED);
if(SrvSocket==INVALID_SOCKET){
_tprintf(_T("Unable to start socket\n"));
return false;
}
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(10000);
sockaddr.sin_addr.s_addr = INADDR_ANY;
/* now bind the socket */
if(bind(SrvSocket, (SOCKADDR *)&sockaddr, sizeof(SOCKADDR_IN))==SOCKET_ERROR){
_tprintf(_T("Unable to bind socket\n"));
return false;
}
if(listen(SrvSocket, 5)==SOCKET_ERROR){
_tprintf(_T("Error listening\n"));
return false;
}
return true;
}
void WorkerThread(void *arg)
{
bool bret= false;
DWORD dwTransferedBytes=0;
CLIENTS *client;
PPER_IO_OPERATION_DATA data;
/* Just sleep for now */
while(true){
_tprintf(_T("Entering while\n"));
bret = GetQueuedCompletionStatus(hIocp,&dwTransferedBytes,(PULONG_PTR)&client,(LPOVERLAPPED *) &data,INFINITE);
if(!bret){
_tprintf(_T("Unable to process completion port\n"));
}
}
//Sleep(10000);
}
void AcceptClientConnections(void *arg)
{
SOCKET ClientSocket;
CLIENTS *c;
_tprintf(_T("Start accepting client connections\n"));
while(true){
ClientSocket = accept(SrvSocket, NULL,NULL);
if(ClientSocket==INVALID_SOCKET){
_tprintf(_T("Unable to accept connection\n"));
continue;
}
/* do an association with completion port */
c = (CLIENTS *)malloc(sizeof(CLIENTS));
c->sock = ClientSocket;
/* associate with completion port */
if(!CreateIoCompletionPort((HANDLE)ClientSocket, hIocp, (ULONG_PTR)c,0)){
_tprintf(_T("Unable to associate with completion port\n: %d"),GetLastError());
}
}
}
Any idea?
thanks in advance.
You are not using the Completion Port correctly, so it has nothing to do, and thus no status to report. Using a Completion Port with sockets is a two-step process, but you are only doing half of the steps.
Read the following MSDN article for details:
Windows Sockets 2.0: Write Scalable Winsock Apps Using Completion Ports
ONe possibility: Check if you have associated the listener socket with the completion port (made this mistake myself). If you haven't the GetQueuedCompletionStatus() will block forever.
Related
I have a UWP (soon to be MacOS also) application that listens for incoming messages. The user can configure which IP Address and Port to listen on. Once the socket connection is listening, the user can also go back into the settings and change the IP Address or Port. I am trying to figure out how to shut down the existing listener and restart it using the new Port / IP Address when the user changes the values. Here is my code that starts the listener. Any help would be appreciated.
private static Socket iobj_listener;
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.ListeningOnSocket = true;
while (true)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
ViewModelObjects.AppSettings.ListeningOnSocket = false;
}
}
SO I could not find any quick answers so had to kind of figure this out on my own. If you see anything wrong with this, please let me know.
First of all I declared an e_Num as follows
public enum ge_SocketStatus
{
e_NotListening = 0,
e_Listening = 1,
e_Restart = 2
}
Then I added a StopListening function to my class that handles all my Socket communications and set the socket status to not listening as follows:
public static async Task StopListening()
{
try
{
if (iobj_listener.Connected)
{
//Wait till the connection ends or 30 seconds - this is so any last messages can be processed.
await Task.Delay(30000);
}
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_NotListening;
iobj_listener.Close(1);
}
catch (Exception ex)
{
App.AppException(ex);
}
}
I then use the value of this enum to know when to end the loop:
public async static Task StartListening()
{
try
{
Debug.WriteLine("Point 1");
IPEndPoint localEndPoint = new IPEndPoint(ViewModelObjects.AppSettings.ServerIPAddress, ViewModelObjects.AppSettings.ServerPort);
// Create a TCP/IP socket.
iobj_listener = new Socket(ViewModelObjects.AppSettings.ServerIPAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
iobj_listener.Bind(localEndPoint);
iobj_listener.Listen(100);
ViewModelObjects.AppSettings.SocketStatus = ge_SocketStatus.e_Listening;
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
{
Debug.WriteLine("Point 2");
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Debug.WriteLine("Waiting for a connection on " + ViewModelObjects.AppSettings.ServerIPAddress.ToString() + "...");
iobj_listener.BeginAccept(
new AsyncCallback(AcceptCallback),
iobj_listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
finally
{
Debug.WriteLine("Point 3");
}
}
This line above
while (ViewModelObjects.AppSettings.SocketStatus == ge_SocketStatus.e_Listening)
used to be
while (true)
so the loop would never end.
One gotcha I found is in the AcceptCallback used in the BeginAccept function of my socket. In this code, I also had to detect if the socket was connected because this function is called one last time after the StartListening loop exits. At the point the socket is not connected so trying to do anything with is, such as EndAccept, causes the application to throw an exception. Below you can see where I added the line
if (listener.Connected)
in order to stop the code from crashing after I had closed the connection.
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
//If we have shut down the socket don't do this.
if (listener.Connected)
{
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Once all StopListening function ends and everything from the sockets is disconnected, I can call start listening again and open the socket on a different IPAddress and or Port.
I hope this helps as I could not find a good solution to this.
I am writing a simple TCP client so that I can connect to an UR (Universal Robot) robot, and send messages (popup XXXX) to the port number 29999, to generate popup messages in the UR screen. UR server does not respond correctly to the gethostbyaddr neither gethostbyname functions when connecting, so, for testing, I connect directly to the IP and Port. The code of the simple TCP client is as follows:
int initTCPSocket(void)
{
struct in_addr ip;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
printf("ERROR opening socket");
return -1;
}
portno = atoi(serverPort.c_str());
if (!inet_aton(serverIP.c_str(), &ip))
printf(" ERROR: error parsing IP address %s", serverIP.c_str());
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htons(ip.s_addr);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
printf("ERROR connecting to server");
return -3;
}
else
printf("Connected to server");
}
The code that actually sends data is:
bool SendDataTCP (tekniker_tcp_comms::SendDataTCP::Request &req, tekniker_tcp_comms::SendDataTCP::Response &res)
{
if (sockfd < 0)
{
ROS_INFO("ERROR in connection");
res.dataSent=false;
return true;
}
size_t msgLength = req.msg.data.length();
//write to connected server.
int n = write(sockfd, req.msg.data.c_str(),(int)msgLength);
if (n < 0)
{
ROS_INFO("ERROR writing to socket");
res.dataSent=false;
}
else
{
ROS_INFO("write %d bytes. Message %s",n, req.msg.data.c_str());
res.dataSent=true;
}
return true;
}
I obtain messages of correct connection, and I can call the Service, and the write function works ok, but, no popup appears in the UR. It seems the UR does not receive correctly the messages.
Connecting to the UR server for popup messages using ncat ( ncat 172.16.205.2 29999) and sending messages manually works fine.
After debugging for some hours, I can not find any cause for this problem. I would appreciate a lot any kind of advise,
Thank you in advance,
After inserting Wireshark to monitor TCP/IP, the problem was with the LF termination character, that was not correctly sent.
Solving this problem the client has worked correctly.
I want to know if my server is online via my ios application. Here's what I'm doing:
Boolean result;
CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFDataRef)(serverIPAddress)); //serverIPAdress = "10.10.10.100:5010"
if(hostRef) {
result = CFHostStartInfoResolution(hostRef, kCFHostAddresses, NULL); // pass an error instead of NULL here to find out why it failed
}
if (!result) { //This means that the host was unreachable
return ;
}
My server is online and I can access it later on in the code(meaning that my connection to the server works perfectly fine). However, I want to be able to detect if my server, on a certain port, is reachable.
Also, if I remove the ":5010" from the ip address, it detects that my server is online (it doesn't go in the "!result" condition) and detects that my server is offline if I put "10.10.10.253" which corresponds to no ip address on my network.
How can I manage to determine if my server is online or not ?
I've looked at this question : Reachability with Address - Server AND Port - iOS 5 but it doesn't work since it always return that it is reachable no matter what ip address I enter
Thanks in advance
One approach could be to open a socket connection to a specific port to see if you get any response back. If not, then the destination is unreachable. For example
#include <arpa/inet.h> //for PF_INET, SOCK_STREAM, IPPROTO_TCP etc
CFRunLoopSourceRef gSocketSource;
void ConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
UInt8 buffer[1024];
bzero(buffer, sizeof(buffer));
CFSocketNativeHandle sock = CFSocketGetNative(socket); // The native socket, used recv()
//check here for correct connect output from server
recv(sock, buffer, sizeof(buffer), 0);
printf("Output: %s\n", buffer);
if (gSocketSource)
{
CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
if (CFRunLoopContainsSource(currentRunLoop, gSocketSource, kCFRunLoopDefaultMode))
{
CFRunLoopRemoveSource(currentRunLoop, gSocketSource, kCFRunLoopDefaultMode);
}
CFRelease(gSocketSource);
}
if (socket) //close socket
{
if (CFSocketIsValid(socket))
{
CFSocketInvalidate(socket);
}
CFRelease(socket);
}
}
void ConnectSocket()
{
//socket
CFSocketContext context = {0, NULL, NULL, NULL, NULL};
CFSocketRef theSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketConnectCallBack , (CFSocketCallBack)ConnectCallBack, &context);
//address
struct sockaddr_in socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sin_len = sizeof(socketAddress);
socketAddress.sin_family = AF_INET;
socketAddress.sin_port = htons(5010);
socketAddress.sin_addr.s_addr = inet_addr("10.10.10.253");
gSocketSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, theSocket, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), gSocketSource, kCFRunLoopDefaultMode);
CFDataRef socketData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&socketAddress, sizeof(socketAddress));
CFSocketError status = CFSocketConnectToAddress(theSocket, socketData, 30); //30 second timeout
//check status here
CFRelease(socketData);
}
Basically, if the server is unreachable at that port, you will most likely get a kCFSocketTimeout for CFSocketError status. If you are looking to parse a specific response back from the server to determine if the server is ready or not, the ConnectCallBack function will be called upon successful socket connection.
This is just a simple example, make sure not to block the UI by calling socket connections on the main thread such as recv()
I've ran into a problem with a simple TCP Client implemented using select.
The problem is that,at the second printf it only displays before it gets to the connect() function then waits for user input. Does connect block the rest of the program until i send something? (The TCP server is also implemented using select but i didn't find anything wrong with it)
I've searched on the web and couldn't find a cause or maybe i didn't search for the right thing..
#include <includes.h>
int main()
{
int sfd;
fd_set rset;
char buff[1024]=" ";
char playerName[20]="";
int nameSet=0;
struct sockaddr_in server;
sfd= socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{ printf("socket not created\n"); return 0; }
bzero(&server,sizeof(struct sockaddr_in));
server.sin_family=AF_INET;
server.sin_port=htons(2020);
inet_aton("127.0.0.1",&server.sin_addr);
//here is the problem after %d which calls the connect() function
printf("Conexion returned:%d \n Name:",connect(sfd,(struct sockaddr *)&server,sizeof(server)));
for(;;)
{
bzero(buff,1024);
FD_ZERO(&rset);
FD_SET(0,&rset);
FD_SET(sfd,&rset);
if(select(sfd+1,&rset,NULL,NULL,NULL)<0)
{
printf("con-lost!\n");
break;
}
if(FD_ISSET(0,&rset))
{
printf("Talk: \n");
scanf("%s",buff);
if(nameSet==0)
{
strcpy(playerName,buff);
nameSet=1;
printf("Hi:%s\n",playerName);
}
if(write(sfd,buff,strlen(buff)+10)<0)
{
break;
}
}
if(FD_ISSET(sfd,&rset)>0)
{
if(read(sfd,buff,1024)<=0)
{
printf("con is off!\n");
break;
}
printf("msg rcd %s\n",buff);
}
} //endfor
close(sfd);
return 0;
} //endmain
The connect function, on a blocking socket, blocks until the connect operation succeeds or fails.
You should be warned that using select with a blocking socket, which is what your program does, does not ensure that your program will not block. When you get a select hit, that does not guarantee that a future operation will not block.
strlen(buff)+10
What's the reasoning behind the +10?
Can you please tell me if there is any example for using GIO Server Socket
(the one which I can open a port and listen on socket requests)?
I would like to use it to 'remote-control' my GTK+ application.
I think you should do something like this:
#define MY_PORT 47110
/* Listener callback, this gets called by GTK+ when
* there's socket activity to handle.
*/
static gboolean cb_listener(GIOChannel *source, GIOCondition condition, gpointer data
{
switch(condition)
{
case G_IO_IN:
/* There's data to be read. */
break;
default:
/* An error has occured, or socket is closed. */
return FALSE; /* This tells GIO to remove the source, might be drastic. */
}
return TRUE; /* This tells GIO that all is fine. */
}
Then elsewhere (in a function, maybe main()):
GSocketListener *listener;
listener = g_socket_listener_new();
g_socket_listener_add_inet_port(listener, MY_PORT, NULL, NULL);
g_io_add_watch(G_IO_CHANNEL(listener), G_IO_IN | G_IO_ERR | G_IO_HUP, cb_listener, NULL);