I have a working socket console server with multithreaded clients app. I've only created console or OpenGL apps. So a windows app is new.
I'm porting my stocket server code to a Win32 API app, and running into some trouble. The server runs, and the clients connect and communicate with each other correctly, but the server window freezes.
From my screenshot, you can see my server messages are being output to my text box. But on reaching the msg loop the app freezes.
I've updated my message loop from
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
to
boolean running = TRUE;
while (running) {
if (PeekMessage(&sys.msg, NULL, 0, 0, PM_REMOVE)) {
if (sys.msg.message == WM_QUIT)
{
running = FALSE;
//exitCode = msg.wParam;
break;
}
TranslateMessage(&sys.msg);
DispatchMessage(&sys.msg);
}
try {
pseucode_socket_checking();
}
catch (std::exception& e) {
running = FALSE;
}
}
pseucode_socket_checking() {
SOCKET incoming = INVALID_SOCKET;
incoming = accept(server_socket, NULL, NULL);
if (incoming == INVALID_SOCKET) return;
...
// create thread for socket.
}
accept() is a blocking function, it waits until a connection is made.
Suggestion: put your accept() loop in a thread.
Windows needs that the message loop is unblocked. When something stucks it (like accept()), the app will freeze. So, let the message loop free from anything blocking.
Related
I am trying to implement an event-driven serial receive in my MFC dialog application.
I am using this class for access to the Win32 APIs dealing with serial ports.
I want to be notified whenever new data is received and from the description it seems like the ReadFileEx function (CSerialPort::ReadExin the Naughter class) could help me achieve this.
ReadFileEx function:
Reads data from the specified file or input/output (I/O) device. It reports its completion status asynchronously, calling the specified completion routine when reading is completed or canceled and the calling thread is in an alertable wait state.
If I have understood it correctly, I can specify a routine (function?) that would get called when serial data is received. But it is the last part that confuses me: "and the calling thread is in an alertable wait state". From the documentation the application can enter an alertable wait state by calling the following functions:
An application uses the MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx, WaitForMultipleObjectsEx, and SleepEx functions to enter an alertable wait state.
Based on this I have the following code in my MFC application:
CSerialPort arduino;
OVERLAPPED overlapped{};
HANDLE hEvent = nullptr;
char command_Arduino[1];
void CTAB1::OnBnClickedButton()
{
hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
ATLASSERT(hEvent != nullptr);
overlapped.hEvent = hEvent;
arduino.SetMask(EV_RXCHAR);
arduino.ReadEx(command_Arduino, 1, &overlapped, Run);
WaitForSingleObjectEx(hEvent, INFINITE, TRUE);
}
However this gives me an unhandled exception:
0xC0000005: Access violation executing location 0x0000000000000000.
Where am I going wrong here? Any help would be greatly appreciated.
Update: Thanks to all the helpful comments, I was able to achieve asynchronous serial receive in a separate worker thread.
Declarations and definitions:
#define WM_USER1 (WM_USER + 1)
CSerialPort arduino;
HANDLE WorkerThread = nullptr;
DWORD WINAPI SerialInputMotorControl_Thread(LPVOID WndPtr);
LRESULT CTAB1::on_wm_user1(WPARAM, LPARAM);
Creating the thread:
void CTAB1::OnBnClickedButtonMotorRun()
{
m_MotorRun.EnableWindow(FALSE); //Disable run button
m_MotorStop.EnableWindow(TRUE); //Enable stop button
//Create worker thread for dealing with serial receive
WorkerThread = CreateThread(NULL, 0, SerialInputMotorControl_Thread, (LPVOID)m_hWnd, 0, NULL);
}
Terminating the thread:
void CTAB1::OnBnClickedButtonMotorStop()
{
m_MotorRun.EnableWindow(TRUE);
m_MotorStop.EnableWindow(FALSE);
if (WorkerThread != nullptr)
{
if (!TerminateThread(WorkerThread, 0)) //Delete worker thread
{
DWORD err = GetLastError();
MessageBox(_T("Error: %d", err), _T("ERROR"), MB_OK | MB_ICONWARNING);
}
}
else
MessageBox(_T("Error: Thread not terminated"), _T("ERROR"), MB_OK | MB_ICONWARNING);
CloseHandle(WorkerThread); //Clean-up
}
The thread:
DWORD WINAPI SerialInputMotorControl_Thread(LPVOID WndPtr)
{
HWND hWnd = (HWND)WndPtr;
char command_Arduino[1] = {};
int prev_command = 100;
while(1)
{
try
{
arduino.Read(command_Arduino, 1);
}
catch (CSerialException& e)
{
if (e.m_dwError == ERROR_IO_PENDING)
{
DWORD dwBytesTransferred = 0;
}
}
char command;
command = command_Arduino[0];
if (prev_command != command)
{
if (command < 1) {
command = 0;
}
if (command > 16) {
command = 16;
}
PostMessage(hWnd, WM_USER1, command, 0); //Send message to GUI
prev_command = command;
}
}
return 0;
}
Then handle the command in the GUI message handler.
I making a simple check login program with mfc. Im using WSAAsyncselect function to make a non blocking socket. Everytimes theres someone login, the server will send back to all current client a message "user x has login in" and then, they will show that message on their message log.
Usually, i can only update value from a button calling WSAAsyncselect funtion after send the data to server.
for example
void CClientDlg::OnBnClickedLogin()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
if ((m_username == "") || (m_password == ""))
{
return;
}
client = socket(AF_INET, SOCK_STREAM, 0);
if (client == INVALID_SOCKET)
{
return;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
char* IPstr = CT2A(IP);
serverAddr.sin_addr.s_addr = inet_addr(IPstr);
int error = connect(client, (sockaddr*)&serverAddr, sizeof(serverAddr));
if (error == SOCKET_ERROR) {
return;
}
modestr = _T("1 ") + m_username + _T(",") + m_password;
SendInfo(modestr);
WSAAsyncSelect(client, m_hWnd, WM_SOCKET, FD_READ | FD_CLOSE);
UpdateData(FALSE);
}
On server, i have this
BEGIN_MESSAGE_MAP(CServerDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(WM_SOCKET, SockMsg)
END_MESSAGE_MAP()
LRESULT CServerDlg::SockMsg(WPARAM wParam, LPARAM lParam) {
if (WSAGETSELECTERROR(lParam))
{
closesocket(wParam);
MessageBox(_T("error"));
}
switch (WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
//accept client
clientSocks.push_back(CLIENT(accept(wParam, NULL, NULL), "unidentified user"));
break;
}
case FD_READ:
{
//check login codes
//check login codes
//check login codes
for (int i = 0; i < num_clients; i++) {
CString message = _T("0 ") + CString(user.c_str()) + _T("login\r\n");
SendResponse(clientSocks[i].clientSocket, message); //a send funtion to send data to
//another socker
}
}
There's anyway to update data automatically after the server send data to these clients
Not answering your question, because this text would be too long for a comment.
I think you are completely misunderstanding how WSAAsyncSelect works. The function does not open a second communication channel from the "client" to the "server" that is based on Windows messages. (There is already a channel: the network connection via sockets.)
You use WSAAsyncSelect to allow that the data transfer happens in the background while the user interface's message loop can keep running and can respond to user activity.
The nMsg argument, WM_SOCKET in your case, is not sent across to a different executable, but is sent to the application itself when the requested event happens. These tell "hey, I've just received data!", "hey, the network connection was closed", "hey, there's now room to write more data".
In your example, it does not make sense to request FD_READ events when the application does not read data.
In addition, since both your "client" and your "server" seem to be user interface applications, both should use WSAASyncSelect. The sending side would listen for FD_WRITE | FD_CLOSE events (because it has to write data), and the receiving side would listen to FD_READ | FD_CLOSE events (because it has to read data).
Note that, in general, the sending side that uses WSAAsyncSelect becomes very complicated to implement: It is not just a simple single write(), because it must be prepared that not all data can be sent at once. Rather, it must keep the data to be sent around, must keep a record of how much has been sent and what has not been sent, yet. Therefore, when the packets are small (a few hundred bytes at most) and infrequent, I would not use asynchronous communication in the sender, and would just hope that networking layer in the OS would be able to cache the data for me and would not block the write() call.
I have a client process that forks a child process to listen for incoming RPCs via the svc_run() method. What I need to do is kill of that child process from the parent and then re-fork the child process providing it a new CLIENT* to a new RPC server.
Here is the bits of my code that are relevant:
// Client Main
CLIENT* connectionToServer;
int pipe[2];
int childPID;
int parentPID;
static void usr2Signal()
{
ServerData sd;
clnt_destroy(connectionToServer);
(void) read(pipe[0], &sd, sizeof(sd));
// Kill child process.
kill(childPID, SIGTERM);
close(pipe[0]);
// RPC connection to the new server
CLIENT *newServerConn =
clnt_create(
sd.ip,
sd.programNum,
1,
"tcp");
if (!newServerConn)
{
// Connection error.
exit(1);
}
connectionToServer = newServerConn;
// Respawn child process.
if (pipe(pipe) == -1)
{
// Pipe error.
exit(2);
}
childPID = fork();
if (childPID == -1)
{
// Fork error.
exit(3);
}
if (childPID == 0)
{
// child closes read pipe and listens for RPCs.
close(pipe[0]);
parentPID = getppid();
svc_run();
}
else
{
// parent closes write pipe and returns to event loop.
close(pipe[1]);
}
}
int main(int argc, char *argv[])
{
/* Some initialization code */
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
// TCP connection error.
exit(1);
}
if (!svc_register(transp, /*other RPC program args*/, IPPROTO_TCP))
{
// RPC register error
exit(1);
}
connectionToServer = clnt_create(
192.168.x.xxx, // Server IP.
0x20000123, // Server RPC Program Number
1, // RPC Version
"tcp");
if (!connectionToServer)
{
// Connection error
exit(1);
}
// Spawn child process first time.
if (pipe(pipe) == -1)
{
// Pipe error
exit(1);
}
childPID = fork();
if (childPID == -1)
{
// Fork error.
exit(1);
}
if (childPID == 0)
{
// Close child's read pipe.
close(pipe[0]);
parentPID = getppid();
// Listen for incoming RPCs.
svc_run ();
exit (1);
}
/* Signal/Communication Code */
// Close parent write pipe.
close(pipe[1]);
// Parent runs in event loop infinitely until a signal is sent.
eventLoop();
cleanup();
}
In my server code I have service call that initiates the new connection. This call is invoked by some other operation on the server.
// Server Services
void newserverconnection_1_svc(int *unused, struct svc_req *s)
{
// This service is defined in the server code
ServerData sd;
/* Fill sd with data:
Target IP: 192.168.a.aaa
RPC Program Number: 0x20000321
... other data
*/
connecttonewserver_1(&sd, connectionToServer); // A client service.
}
Back in my client I have the following service:
// Client Service
void connecttonewserver_1_svc(ServerData *sd, struct svc_req *s)
{
// Send the new server connection data to the parent client processs
// via the pipe and signal the parent.
write(pipe[1], sd, sizeof(sd));
kill(parentPID, SIGUSR2);
}
My problem is, everything runs fine until I initiate the new connection. I do not get into any of my error sections, but about 5 seconds after setting up the new connection, my client becomes unresponsive. It does not crash and the child process seems to still be alive also, but my client will no longer receive RPCs or show any print statements when my events defined in the event loop for the parent are triggered by mouse clicks. I am probably doing something slightly wrong to spawn this new RPC loop for the child process, but I can't see what. Any ideas?
So this solution achieves the result I was looking for, but is definitely far from perfect.
static void usr2Signal()
{
ServerData sd;
// clnt_destroy(connectionToServer); // Removed this as it closes the RPC connection.
(void) read(pipe[0], &sd, sizeof(sd));
// Removed these. Killing the child process also seems to close the
// connection. Just let the child run.
// kill(childPID, SIGTERM);
// close(pipe[0]);
// RPC connection to the new server
CLIENT *newServerConn =
clnt_create(
sd.ip,
sd.programNum,
1,
"tcp");
if (!newServerConn)
{
// Connection error.
exit(1);
}
// This is the only necessary line. Note that the old
// connectionToServer pointer was not deregistered/deallocated,
// so this causes a memory leak, but is a quick fix to my issue.
connectionToServer = newServerConn;
// Removed the rest of the code that spawns a new child process
// as it is not needed anymore.
}
I have made my first linux service with C++.
pid_t pid, sid;
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
if (pid>0) {
exit(EXIT_SUCCESS);
}
umask(0);
sid = setsid();
if (sid < 0) {
exit(EXIT_FAILURE);
}
if ((chdir("/")) < 0) {
exit(EXIT_FAILURE);
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
while (1) {
????????
//sleep(10);
}
exit(EXIT_SUCCESS);
What it would do is to wait for my signal and when it receives it to do some tasks and then again wait for my next signal.
I would send my signal (or whatever) somehow from within my c++ app that runs on same machine. Seems like a mechanism of semaphore between two apps. But in this case one is a linux service, and I do not know how the service could wait my signal.
How could I achieve this? What are my alternatives?
Thanks.
Note: The word "signal" caused to confusion. I didn't intend to use that word as technically. I just mean that I need to talk to my linux service from within my cpp app.
NOTE 2: Using signal is not useful because in its handler almost doing any thing is unsafe, whereas I need to do lots of things. (I dont know if I could start a thread, at least!)
Here is an example of an handler that takes care of SIGHUP and SIGTERM, your program could send these signals using kill -9 processid or kill -HUP processid of course there is a few other signals you could use for this purpose check man signal
void handler (int signal_number){
//action
exit(1);
}
And in the main program
struct sigaction act;
struct sigaction act2;
memset (&act, 0, sizeof (act));
memset (&act2, 0, sizeof (act2));
act.sa_handler = handler;
act2.sa_handler = handler;
if (sigaction (SIGHUP, &act, NULL) < 0) {
perror ("sigaction");
}
if (sigaction (SIGTERM, &act, NULL) < 0) {
perror ("sigaction");
}
//wait here for ever or do something.
Finally I have found the right keywords to google what I needed to know.
Here are the alternative ways to communicate between different processes:
http://www.tldp.org/LDP/lpg/node7.html
Hey, im doing some client/server stuff in a windows service. Pretty much new to this stuff.
The problem I'm encountering is that when I try to stop the service through Service Manager, it crashes. I added some MessageBoxes code, to trace where they are crashing and I found that when it closes the listener socket it crashes!!!
I tried to run the service as a console application, and by myself called the function which is called SERVICE__CONTROL__STOP event is received so that I may reproduce the bug and debug easily. But it is working fine. The windows service is only crashing when I stop it through Service Manager
Here is some code
The main function
int main(int argc, char* argv[])
{
// Create the service object
CTestService CustomServiceObject;
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
std::cerr << "MFC failed to initialize!" << std::endl;
return 1;
}
// Parse for standard arguments (install, uninstall, version etc.)
if (! CustomServiceObject.ParseStandardArgs(argc, argv))
{
// StartService() calls ::StartServiceCtrlDispatcher()
// with the ServiceMain func and stuff
CustomServiceObject.StartService();
}
// When we get here, the service has been stopped
return CustomServiceObject.m_Status.dwWin32ExitCode;
}
The Service Handler callback function
// static member function (callback) to handle commands from the
// service control manager
void CNTService::Handler(DWORD dwOpcode)
{
// Get a pointer to the object
CNTService* pService = m_pThis;
pService->DebugMsg("CNTService::Handler(%lu)", dwOpcode);
switch (dwOpcode) {
case SERVICE_CONTROL_STOP: // 1
pService->SetStatus(SERVICE_STOP_PENDING);
pService->OnStop();
// ..
// ..
// other event handling
// ..
// ..
}
the OnStop() function
void CTestService::OnStop()
{
m_sListener.ShutDown(2);
m_sConnected.ShutDown(2);
MessageBox(NULL, "After Shutdown", NULL, IDOK);
m_sConnected.Close();
MessageBox(NULL, "Closed connected socket", NULL, IDOK);
// crashes here when I try to stop through service manager
// but if I run as console application works fine and terminates successfully
m_sListener.Close();
MessageBox(NULL, "Closed listener socket", NULL, IDOK);
::PostThreadMessage(m_dwThreadID, WM_QUIT, NULL, NULL);
MessageBox(NULL, "After PostThreadMessage", NULL, IDOK);
}
EDIT: If a connection is made (client connects to the server) and the client closes the connection and then the service is stopped nothing crashes. It only crashes if the socket is listening and no connection is accepted or the client doesnt closes the connection and the service is stopped :)
I guess its clear!
Try adding:-
WSADATA data;
if(!AfxSocketInit(&data))
AfxMessageBox("Failed to Initialize Sockets",MB_OK| MB_ICONSTOP);
to your thread or class initialiser.
The problem is that you're most likely using the socket from multiple threads. Multiple threads and CAsyncSocket do not mix - in fact, as noted by the documentation.
Usually you would push the socket into it's own Worker Thread then you would signal it to close when you needed it to.