Introduction
Everyone should have an idea on accessing Winsock in eMbedded Visual Basic 3.0. Its 100% easy and straight forward as what I did in Visual Basic. But how about eMbedded Visual C++ 3.0?
The Winsock for MS Windows CE does not support WSAAsyncSelect
. Hence, we need to write a chunk of code as well as the synchronization thread to handle the incoming and outgoing data ourselves.
Using the code
The posted code is the entire sample project. So you might need to cut & paste the following function in order to utilize the piece of code in your own project. Don't worry, the code is easy to identify and all you need is to filter out all my demo project GUI interface control code.
Below are the three basic functions and the two synchronization threads you need to copy:
int InitSocket (HWND); void OpenSocket (HWND); void CloseSocket(HWND);
DWORD WINAPI StartListen (LPVOID pParam);
DWORD WINAPI ReadInBuffer (LPVOID pParam);
Once you have copied the code, you need to call the above mentioned three functions in sequence. As each of them is to perform a specific task. Em... Lets look at the first function InitSocket
as below. Basically, all it does is just initialize the Winsock component (version 1.1) by calling the WSAStartup
API before we can proceed to create/use any socket.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
{
MessageBox(hWnd, TEXT("Fail to initialize the Winsock DLL!"),
TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
return 1;
}
else
return 0;
Second, we need to create a new socket to listen to an incoming request (connect to a host) on a specific port number and accept the connection request (establish the connection). But you will notice there is some extra code under the OpenSocket
which is used to handle the GUI control for determining whether the socket going to be created is in Server mode or Client mode. This is because both will have two different logic flow and characteristics.
Hence, if the socket going to be created is in server mode, all you need is proceed to create the synchronization thread (StartListen
). Else, you will need to execute the following code to establish a connection to the specific host followed by creating the ReadInBuffer
synchronization thread.
NOTE: All the non-relevant GUI code is filtered out in the following display code (but not in the attached demo project code). You may need to add your own GUI control/updated code into this function.
memset(&sckAddress, 0, sizeof(sockaddr_in));
sckClient = socket(AF_INET, SOCK_STREAM, 0);
sckAddress.sin_port = htons(atoi(port));
sckAddress.sin_family = AF_INET;
sckAddress.sin_addr.s_addr = inet_addr(host);
if(connect(sckClient, (struct sockaddr *)&sckAddress,
sizeof(sckAddress)) != SOCKET_ERROR)
hThread2 = CreateThread(NULL, 0, ReadInBuffer, hWnd, 0, &dwThreadID);
else
MessageBox(hWnd, TEXT("Client~Fail to establish the connection!"),
TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
What is inside the StartListen
synchronization thread? When you look into the code, you'll find that it is an infinite do...while
loop in this thread and perform a checking on the socket state on every loop until it gets a valid socket handle as show in the code below:
if(sckServer != INVALID_SOCKET)
{
sckAddress.sin_port = htons(atoi(port));
sckAddress.sin_family= AF_INET;
sckAddress.sin_addr.s_addr = INADDR_ANY;
bind(sckServer, (struct sockaddr *)&sckAddress, sizeof(sckAddress));
listen(sckServer, 1);
do
{
fds;
tv.tv_sec = 1;
tv.tv_usec = 1;
FD_ZERO (&fds);
FD_SET (sckServer, &fds);
if (select(0, &fds, NULL, NULL, &tv) == 0)
continue;
if (FD_ISSET(sckServer, &fds) != 0)
{
sckClient = accept(sckServer, NULL, 0);
closesocket(sckServer);
sckServer = INVALID_SOCKET;
SetDlgItemText(hWnd, IDC_STATUS1, TEXT("Connected"));
hThread2 = CreateThread(NULL, 0, ReadInBuffer,
hWnd, 0, &dwThreadID);
break;
}
}while (sckServer != INVALID_SOCKET);
}
else
MessageBox(hWnd, TEXT("Server~Fail to open the socket!"),
TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
At this stage, you still can not receive any data from the host (client) connection. So, the ReadInBuffer
synchronization thread is heard of the entire demo application which enables you to receive any data from host (client) connection.
Hence, lets take a look on the ReadInBuffer
coding and understand more about its operation.
HWND hWnd = NULL;
char *Buff=NULL;
TCHAR *wBuff=NULL;
int err;
hWnd = (HWND)pParam;
wBuff = new TCHAR[1024];
Buff = new char[1024];
if (sckClient != INVALID_SOCKET )
{
while (true)
{
memset(wBuff, TEXT('\0'), 1024*sizeof(TCHAR));
memset(Buff, '\0', 1024);
err = recv(sckClient, Buff, 1024, 0);
if (err == SOCKET_ERROR || err <= 0)
{
CloseSocket(hWnd);
break;
}
else
{
mbstowcs(wBuff, Buff, 1024);
SetDlgItemText(hWnd, IDC_EDIT3, wBuff);
}
}
}
delete Buff;
ExitThread(WM_QUIT);
return 0;
From the above code, there is an infinite while
loop which will constantly check the socket status and it will break the looping when there is an invalid socket detected.
Last, we must destroy the socket when not in use or upon detecting the host (client) connection is lost. Therefore, the CloseSocket
function is straight forward as shown below.
if(sckServer != INVALID_SOCKET)
{
if (closesocket(sckServer) == 0)
sckServer = INVALID_SOCKET;
else
MessageBox(hWnd, TEXT("Server~Fail to close the socket."),
TEXT("MySocket"), MB_OK | MB_ICONEXCLAMATION);
}
P.S If you need to get the local machine IP address, all you need is call the GetLocalIP
function as included in the demo application.
Will do.