I'm writting an server using the multithread technique.
The idea is :
-I will use a socket (m_Server) to accept when the client connect.
-After accept, I'll use another port (t_Socket[i]) to communicate with that client.
It's simple like that. But it's took me about a week to get this far (Because I have a little bit knowledge about socket and I didn't know anything about multithread before).
Here is my code on server :
#include "stdafx.h"
#include "testServer.h"
#include "afxsock.h"
#include "conio.h"
#include "Player.h"
#include <stdio.h>
#include "../functions.h"
#include <iostream>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define MAX_THREADS 1
CSocket *p_Socket=new CSocket[MAX_THREADS];
CWinApp theApp;
int count=0;
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
int i=count;
cout<<"Send : ";
m_Send(p_Socket[i]);
return 1;
}
int m_Send(CSocket &m_Socket)
{
char Msg[100];
int MsgSize;
cin.getline(Msg,100);
MsgSize=strlen(Msg);
m_Socket.Send(&MsgSize,sizeof(int));
m_Socket.Send(Msg,MsgSize);
return MsgSize;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
if(AfxSocketInit()==false)
{
cout<<"Initialize Library Failed"<<endl;
return false;
}
int playerIndex=0;
CSocket m_Server;
HANDLE hThreadArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
if(m_Server.Create(5770)==0)
{
cout<<"Can not create Socket"<<endl;
cout<<m_Server.GetLastError();
}
else
{
cout<<"Successfully initialize server"<<endl;
}
m_Server.Listen(5);
for(int i=0;i<MAX_THREADS;i++)
{
if(m_Server.Accept(p_Socket[i]))
{
cout<<"Player "<<i+1<<" connected!"<<endl;
}
}
for(int i=0;i<MAX_THREADS;i++)
{
hThreadArray[i]=CreateThread(
NULL,
0,
MyThreadFunction,
NULL,
0,
dwThreadIdArray);
//m_Send(p_Socket[i]); (1)
count++;
}
WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
for(int i=0;i<MAX_THREADS;i++)
{
p_Socket[i].Close();
}
m_Server.Close();
cout<<"Close all connections"<<endl;
getch();
}
}
else
{
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
The problem is :
-After the m_Server accept a connection. The p_Socket in the multithread function doesn't receive the right connection.
-But, look at the line I write a comment with number (1) : //m_Send(p_Socket[i]); (1).
If I run that line instead of the CreateThread line, the program will doing well. But that will make my program become single threaded.
BTW, the MAX_THREADS I set it to 1 because I want to test the code in the simpliest case. I think the problem in my code is the p_Socket[i] can't pass into a multithread function.
I have search for a solution about this for nearly 2 days. So I decided to post a question here hoping for someone will take a look at it.
Thank you for reading my question and sorry about my bad English.
One big problem is that you use a 'count' global to communicate the array index to the handler thread. That is just wrong and will not work.
Instead of passing the 'dwThreadIdArray' as the last parameter in the CreateThread API, pass in the counter 'i'.
Also, the overall structure of your server is atypical. Usually, the Accept() loop runs forever and ceates a client<>server handler thread immediately after Accept() returns, passing a socket handle/pointer as the last void* param. Your code seems to wait, running a for-loop, until MAX_THREADS clients have connected before creating the handler threads in yet another loop. It this your intended behaviour?
Related
I have a small test code. My assumption is in below code, since I didn't set flag to stop the thread, then in the line of GetExitCodeThread(). it should return TRUE and return code is STILL_ACTIVE.
While in actual test, the result is:
Every time, the return value of GetExitCodeThread() is FALSE, so in main(), the while loop never entered. Could somebody please tell me the reason? What's wrong in my code. Thanks.
// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "afxwin.h"
bool bExit = false;
HANDLE hOriginalThread;
static UINT ThreadFunc(LPVOID pParam)
{
int iCount = 0;
printf("start thread--ThreadFunc\n");
printf("Thread loop start: --ThreadFunc");
while (!bExit)
{
iCount++;
if (iCount % 50 == 0)
printf(".");
}
printf("Thread loop end: %d--ThreadFunc\n", iCount++);
printf("end thread--ThreadFunc\n");
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
hOriginalThread = AfxBeginThread(ThreadFunc, (LPVOID)0, THREAD_PRIORITY_NORMAL, 0, 0);
Sleep(500);
DWORD dwEC;
int iTry = 0;
BOOL bStatus;
bStatus = GetExitCodeThread(hOriginalThread, &dwEC);
if (!bStatus)
{
printf("error GetExitCodeThread: %d--Main\n", GetLastError());
}
while (bStatus && dwEC == STILL_ACTIVE)
{
printf("Check Thread in active: %d--Main\n", iTry);
Sleep(1);
iTry++;
if (iTry>5)
{
printf("Try to terminate Thread loop: %d--Main\n", iTry++);
TerminateThread(hOriginalThread, 0);// Force thread exit
}
bStatus = GetExitCodeThread(hOriginalThread, &dwEC);
}
hThread = NULL;
printf("End Main --Main\n");
return 0;
}
AfxBeginThread() returns a CWinThread* object pointer, not a Win32 HANDLE like CreateThread() does. So GetExitCodeThread() fails due to an invalid thread handle, which GetLastError() should have told you.
CWinThread has an operator HANDLE() to get the proper Win32 handle of the thread, eg:
CWinThread *pThread = AfxBeginThread(...);
if (!pThread) ... // error handling
hOriginalThread = *pThread;
The reason your code even compiles is because you are likely not compiling with STRICT Type Checking enabled, so HANDLE is just a simple void*, which any kind of pointer can be assigned to. If you enable STRICT, HANDLE will not be void* and assigning the return value of AfxBeginThread() directly to hOriginalThread will cause a compiler error due to a type incompatibility.
I'm new to C++ and decided to challenge myself with a small console game. To avoid typical flickering.
Fromm what I got from MSDN docs I should be using a Console Buffer, but I took it easy and started from simple things like changing Window title and resizing it.
The small program I wrote was meant to do just that, but for some reason I get Error Code 6 (should be "invalid handle") when I execute the SetConsoleWindowInfo.
Anyone who can point me in the right direction with this? Thank you in advance
#include <windows.h>
#include <stdio.h>
#include <iostream>
HANDLE wHandle, bHandle;
SMALL_RECT wSize = { 0,0,100,100 };
int main() {
wHandle = GetConsoleWindow();
if (wHandle == NULL) {
printf("Handle is Null");
}
SetConsoleTitle(L"NewTitle");
if (!SetConsoleWindowInfo(wHandle, TRUE, &wSize)) {
printf("SetConsoleWindowInfo (%d)\n", GetLastError());
}
getchar();
return 0;
}
Maybe this will help:
#include <windows.h>
#include <stdio.h>
#include <iostream>
HANDLE wHandle, bHandle;
//SMALL_RECT wSize = { 0,0,100,100 }; // If SetConsoleWindow fails with code 87, then this is too big!
SMALL_RECT wSize = { 0,0,60,20 }; // Works on my screen!
int main() {
// wHandle = GetConsoleWindow();
wHandle = GetStdHandle(STD_OUTPUT_HANDLE); // See comment by RbMm
if (wHandle == NULL) {
printf("Handle is Null");
}
// SetConsoleTitle(L"NewTitle"); // Don't use a wide character string!
SetConsoleTitle("NewTitle");
if (!SetConsoleWindowInfo(wHandle, TRUE, &wSize)) {
printf("SetConsoleWindowInfo (%d)\n", GetLastError());
}
getchar();
return 0;
}
Feel free to ask, if you don't understand anything I've changed (or why I've changed it), but the comments address some of the issues.
I am working on an installer project in Advanced Installer 10.2. I found out that I can use a DLL for serial validation then I found this resource on their website.
I succeeded in building that DLL, here is my code:
// SerialValidationLib.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "SerialValidationLib.h"
#include <Msi.h>
#include <MsiQuery.h>
#include <MsiDefs.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
}
}
else
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: GetModuleHandle failed\n"));
nRetCode = 1;
}
return nRetCode;
}
UINT __stdcall ValidateSerial_Sample(MSIHANDLE hInstall)
{
TCHAR szPidKey[256];
DWORD dwLen = sizeof(szPidKey)/sizeof(szPidKey[0]);
//retrive the text entered by the user
UINT res = MsiGetProperty(hInstall, _T("PIDKEY"), szPidKey, &dwLen);
if(res != ERROR_SUCCESS)
{
//fail the installation
return 1;
}
bool snIsValid = false;
//validate the text from szPidKey according to your algorithm
//put the result in snIsValid
TCHAR * serialValid;
if(snIsValid)
serialValid = _T("TRUE");
else
{
//eventually say something to the user
MessageBox(0, _T("Serial invalid!"), _T("Message"), MB_ICONSTOP);
serialValid = _T("FALSE");
}
res = MsiSetProperty(hInstall, _T("SERIAL_VALIDATION"), serialValid);
if(res != ERROR_SUCCESS)
{
return 1;
}
//the validation succeeded - even the serial is wrong
//if the SERIAL_VALIDATION was set to FALSE the installation
//will not continue
return 0;
}
I also imported it to Advanced Installer, look here:
But when I run the installer, and try to proceed with the installation, after serial insertion point, I get this error message:
Where is my mistake? Does anybody know a good tutorial about this? I searched on the internet, but nothing helps me...
You could have two problems:
either you have typed the method name instead of picking it from the combo loaded by Advanced Installer. In this case the installer fails to call the method from the DLL, as it cannot find it.
or, there is a problem with your code, in which case you need to debug it, as you would do with a normal custom action, attaching from VS (add a mesagebox with a breakpoint after it).
I want to use ptrace to check what system calls a program spawned by my program makes. I started out from this tutorial as it was explained in an answer to my previous question. I modified the code by adapting it to the platform I'm using (SLES 11 64 bit), and put together the following test code that prints out every system call the spawned process makes:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
run();
}
return 0;
}
It works pretty well: it prints the id of the system calls made by the program (actually it prints each one twice, once at entry and once for exit, but that doesn't matter now). However, my program needs to do other things to do other than checking the system calls, so I decided to move the checking to a separate thread (I'm more comfortable with C++ than C, so I did it the C++ way, but I don't think that matters). Of course in this thest program, I only start the thread and then join it.
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
#include <boost/thread.hpp>
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
boost::thread t(run);
t.join();
}
return 0;
}
This time I get an error message:
Child process id = 24682.
Got event from 24682.
ptrace: No such process
Why is this? I tried searching for an answer but found nothing like this. I found that ptrace won't trace threads started by the child process, but that's another thing needs to be dealed with later. Is that even possible to check the child process from a different therad?
The other strange thing is that in my real application I do basically the same thing (but from a much more complicated context: classes, mutexes etc.), and I get a different kind of error. Instead of ptrace returning with an error, wait doesn't even return for system calls on the child process (and the child process doesn't even stop). On the other hand, wait works as expected when the child process exits.
As far as I can tell, ptrace allows just one tracer per process. This means that if you try to attach, which you can try and force it with PTRACE_ATTACH, you will receive an error, telling that ptrace was not able to attach to the specified process.
Thus, your error appears because your thread is not attached to the child process, and this way, when you try to ptrace it, it fails, sending a -ESRCH code.
Furthermore, you can have a look at this post here, it might answer some other questions you might have apart from this one.
i use this (http://www.codeproject.com/KB/IP/Socks.aspx) lib in my socket programing in c++
and copy the socks.h in include folder and write this code:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>
#include "socks.h"
#define PORT 1001 // the port client will be connecting to
#define MAXDATASIZE 100
static void ReadThread(void* lp);
int socketId;
int main(int argc, char* argv[])
{
const char temp[]="GET / HTTP/1.0\r\n\r\n";
CSocks cs;
cs.SetVersion(SOCKS_VER4);
cs.SetSocksPort(1080);
cs.SetDestinationPort(1001);
cs.SetDestinationAddress("192.168.11.97");
cs.SetSocksAddress("192.168.11.97");
//cs.SetVersion(SOCKS_VER5);
//cs.SetSocksAddress("128.0.21.200");
socketId = cs.Connect();
// if failed
if (cs.m_IsError)
{
printf( "\n%s", cs.GetLastErrorMessage());
getch();
return 0;
}
// send packet for requesting to a server
if(socketId > 0)
{
send(socketId, temp, strlen(temp), 0);
HANDLE ReadThreadID; // handle for read thread id
HANDLE handle; // handle for thread handle
handle = CreateThread ((LPSECURITY_ATTRIBUTES)NULL, // No security attributes.
(DWORD)0, // Use same stack size.
(LPTHREAD_START_ROUTINE)ReadThread, // Thread procedure.
(LPVOID)(void*)NULL, // Parameter to pass.
(DWORD)0, // Run immediately.
(LPDWORD)&ReadThreadID);
WaitForSingleObject(handle, INFINITE);
}
else
{
printf("\nSocks Server / Destination Server not started..");
}
closesocket(socketId);
getch();
return 0;
}
// Thread Proc for reading from server socket.
static void ReadThread(void* lp)
{
int numbytes;
char buf[MAXDATASIZE];
while(1)
{
if ((numbytes=recv(socketId, buf, MAXDATASIZE-1, 0)) == -1)
{
printf("\nServer / Socks Server has been closed Receive thread Closed\0");
break;
}
if (numbytes == 0) break;
buf[numbytes] = '\0';
printf("Received: %s\r\n",buf);
send(socketId,buf,strlen(buf),0);
}
}
but when compile this i get an error .
pls help me
thanks
To use sockets you need to link your executable with Ws2_32.lib. It will fix the link error that you have mentioned in comments.
According to the MSDN documentation for closesocket, you need to link to Ws2_32.lib.