SOCKET sock;
char buff[256];
int done = 0;
•
•
•
while (!done) {
Nbytes = recv(sock, buff, 65);
If (Nbytes == -1) {
printf("error\n");
return;
}
DoComputationOnData(buff);
}
Figure 3 Multithreaded Blocking Socket
Common Variables
// Initialize critical section (data) and create an auto-reset
// event (hEvent) before creating the two threads
CRITICAL_SECTION data;
HANDLE hEvent;
TCHAR buff[MAX_BUFFER_SIZE];
int nbytes;
Reader Thread
void ReadThread(void)
{
int nTotal = 0, nRead = 0, nLeft = 0, nBytes = 0;
while (!done)
{
nTotal = 0;
nLeft = NUM_BYTES_REQUIRED;
while (nTotal != NUM_BYTES_REQUIRED)
{
ReserveCriticalSection(&data);
nRead = recv(sock, &(buff[MAX_BUFFER_SIZE – nBytes]),
nLeft);
if (nRead == -1) {
printf("error\n");
ExitThread();
}
nTotal += nRead;
nLeft -= nRead;
nBytes += nRead;
ReleaseCriticalSection(&data);
}
SignalEvent(hEvent);
}
}
Computation Thread
void ProcessThread(void)
{
WaitForSingleObject(hEvent);
ReserveCriticalSection(&data);
DoSomeComputationOnData(buff);
// Remove the processed data from the input buffer, and shift the
// remaining data to the start of the array
nbytes -= NUM_BYTES_REQUIRED;
ReleaseCriticalSection(&data);
}
Figure 4 Making a Socket Nonblocking
SOCKET s;
unsigned long ul=1;
int nRet;
s = socket(AF_INET, SOCK_STREAM, 0);
nRet = ioctlsocket(s, FIONBIO, (unsigned long *)&ul);
if (nRet == SOCKET_ERROR) {
// failed to put socket into nonblocking mode
}
Figure 5 WSAEWOULDBLOCK Errors
Function Name | Description |
accept | The application has not received a connection request. Call accept again to check for a connection. |
closesocket | In most cases this means that setsockopt was called with the SO_LINGER option and a timeout was set. |
connect | The connection is initiated. Call connect again to check for completion. |
recv or recvfrom | No data has been received. Check again later using select. |
send and sentto | No buffer space available for outgoing data. Try again later. |
Figure 6 Checking for Socket State with select
SOCKET s;
fd_set fdread;
int ret;
•
•
•
// Create a socket and establish a connection
•
•
•
FD_ZERO(&fdread); // clear the fd_set
FD_SET(s, &fdread); // add socket s to the socket set
if ((ret = select(0, &fdread, NULL, NULL, NULL)) == SOCKET_ERROR)
{
// error condition
}
if (ret > 0)
{
// At least 1 socket has pending data, in this case only s
}
Figure 7 Valid Socket Options
Level | Option Name | Specific API | Protocol |
SOL_SOCKET | SO_SECURE | Both | Winsock |
SO_DEBUG | Both | Winsock | |
SO_ACCEPTCONN | Both | Winsock | |
SO_RESUSEADDR | Both | Winsock | |
SO_KEEPALIVE | Both | Winsock | |
SO_BROADCAST | setsockopt | Winsock | |
SO_LINGER | Both | Both | |
SO_SNDBUF | getsockopt | Winsock | |
SO_RCVBUF | getsockopt | Winsock | |
SO_TYPE | getsockopt | Winsock | |
SO_SNDTIMEO | Both | Winsock | |
SO_RCVTIMEO | Both | Winsock | |
IPPROTO_TCP | TCP_NODELAY | Both | Winsock |
IPPROTO_IP | IP_MULTICAST_TTL | Both | Winsock |
IP_MULTICAST_IF | Both | Winsock | |
IP_MULTICAST_LOOP | Both | Winsock | |
IP_ADD_MEMBERSHIP | setsockopt | Winsock | |
IP_DROP_MEMBERSHIP | setsockopt | Winsock | |
SOL_IRLMP | IRLMP_ENUMDEVICES | getsockopt | IrSock |
IRLMP_IAS_QUERY | getsockopt | IrSock | |
IRLMP_SEND_PDU_LEN | getsockopt | IrSock | |
IRLMP_EXCLUSIVE_MODE | setsockopt | IrSock | |
IRLMP_IRLPT_MODE | setsockopt | IrSock | |
IRLMP_9WIRE_MODE | setsockopt | IrSock | |
IRLMP_SHARP_MODE | setsockopt | IrSock | |
IRLMP_IAS_SET | setsockopt | IrSock |
Figure 8 WSAIoctl and ioctlsocket Options
Function | Option |
WSAIoctl | FIONBIO |
FIONREAD | |
SIOCATMARK | |
SO_SSL_GET_FLAGS | |
SO_SSL_SET_FLAGS | |
SO_SSL_GET_PROTOCOLS | |
SO_SSL_SET_PROTOCOLS | |
SO_SSL_GET_VALIDATE_CERT_HOOK | |
SO_SSL_SET_VALIDATE_CERT_HOOK | |
SO_SSL_GET_CONNECTION_INFO | |
ioctlsocket | FIONBIO |
FIONREAD | |
SIOCATMARK |
Figure 9 Simple IrSock Client and Server
IrClient.c
#include <windows.h>
#include <winsock.h>
#include <af_irda.h>
#define MAX_RETRIES 5
#define SEND_MESSAGE "This is a test!"
int LookupIrService(SOCKET sock, DEVICELIST *devList, int *nDevices,
int maxretries)
{
int cnt=0, devListLen = sizeof(*devList);
devList->numDevice = 0;
while ((devList->numDevice == 0) && (cnt <= maxretries))
{
getsockopt(sock, SOL_IRLMP, IRLMP_ENUMDEVICES, (char *)
devList, devListLen);
if (*nDevices = devList.numDevice)continue;
cnt++;
Sleep(500);
}
if (cnt > maxretries) // Server device could not be located
return 0;
else
return 1;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow )
{
SOCKET sock;
SOCKADDR_IRDA iraddr = {AF_IRDA, 0,0,0,0, "MyServer"};
DEVICELIST devList;
int nDevices = 0, idx = 0, nRead, i;
char recvBuff[256];
TCHAR urecvBuff[256];
Sock = socket(AF_IRDA, SOCK_STREAM, 0);
DevList.numDevice = 0;
//
// Look for any IrSock services out there
//
if (LookupIrService(sock, &devList, &nDevices, MAX_RETRIES) == 0)
{
MessageBox(NULL,
TEXT("No IrDA services found"), NULL,
MB_OK);
Return 1;
}
for(i=0; i < nDevices ;i++)
{
// Copy the device ID into the SOCKADDR_IRDA structure used
// in the connect() call
for (idx = 0; idx <= 3; idx++)
iraddr.irdaDeviceID[idx] = devList.Device[i].irdaDeviceID[idx];
// Attempt a connection
if (connect(sock, (struct sockaddr *)&iraddr,
sizeof(SOCKADDR_IRDA)) == SOCKET_ERROR)
{
MessageBox(NULL, TEXT("Unable to estabilish a\
Connection to a server"),
NULL, MB_OK);
continue;
}
send(sock, SEND_MESSAGE, strlen(SEND_MESSAGE)+1, 0);
nRead = recv(sock, recvBuff, sizeof(recvBuff), 0);
// Convert ASCII message to Unicode
//
for(idx=0; idx < nRead ;idx++)
urecvBuff[idx] = recvBuff[idx];
MessageBox(NULL, urecvBuff, TEXT("IR Client"), MB_OK);
Closesocket(sock);
Break;
}
return 0;
}
IrServer.c
#include <windows.h>
#include <af_irda.h>
#define SEND_MESSAGE "Hello Client!"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow )
{
WSAData wsaData;
SOCKET ServerSock, // Socket for the Server
ClientSock; // Socket for the Client
SOCKADDR_IRDA iraddr = {AF_IRDA, 0, 0, 0, 0, "MyServer"};
char asciiBuff[250]; // ASCII String
TCHAR unicodeBuff[250]; // UNICODE String
int idx = 0, done = 0, nRead;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
{
MessageBox(NULL, TEXT("Unable to perform WSAStartup"), NULL,
MB_OK);
Return 1;
}
//
// Allocate a stream socket in the IrDA address domain
//
if ((ServerSock = socket(AF_IRDA, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf(unicodeBuff, TEXT("socket call failed with: %d"),
WSAGetLastError());
MessageBox(NULL, unicodeBuff, NULL, MB_OK);
Return 1;
}
if (bind(ServerSock, (struct sockaddr *)&iraddr, sizeof(iraddr)) != 0)
{
wsprintf(unicodeBuff, TEXT("Unable to bind to socket: %d"),
WSAGetLastError());
MessageBox(NULL, unicodeBuff, NULL, MB_OK);
Return 1;
}
listen(ServerSock, 8);
while (!done)
{
// Wait for a client to contact us. Blocking call.
//
ClientSock = accept(ServerSock, 0, 0);
// Receive a string from the client
nRead = recv(ClientSock, asciiBuff, sizeof(asciiBuff), 0);
// Convert string from client to Unicode
for (idx = 0; idx <= nRead; idx++)
unicodeBuff[idx] = asciiBuff[idx];
// Display string received from client
MessageBox (NULL, unicodeBuff, TEXT("IR Server"), MB_OK);
// Send a greeting back to the Client
send(ClientSock, SEND_MESSAGE, strlen(SEND_MESSAGE)+1, 0);
// Close Client Socket
closesocket(ClientSock);
}
closesocket(ServerSock); // Close Server Socket
WSACleanup();
return 0;
}