This article describes how to send multiple-bytes (chars) out-of-band data by using Winsock. The sample applications are created in Microsoft Visual C++.
Because this OOB mechanism is not directly supported at the Microsoft Windows socket level, you must implement this OOB mechanism at the application level. This is not true OOB data. In this sample application, you create two sockets on the client side, also known as the sender side, to send OOB data and normal data. On the server side, also known as the receiver side, you use two sockets to process the data in two threads. One thread is for OOB data. The other thread is for normal data.
To simulate the OOB mechanism, you must synchronize these two threads. Make sure that the thread that processes OOB data has higher priority than the thread that processes normal data.
This sample application describes one way to send multi-byte OOB data. You may have to revise the code to make the code work in your environment.
You must include a reference to the Winsock Library file, Ws2_32.lib, to make the code compile.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <assert.h>
#include <winsock.h>
main(int argc, char *argv[])
{
int nErr, nSize;
WSADATA wsaData;
SOCKET myOOBSocket = INVALID_SOCKET;
SOCKET myNormalSocket = INVALID_SOCKET;
unsigned short nPort; // Listen for the port number.
struct sockaddr_in remoteIp;
if (argc!=3)
{
printf("TcpDemoC <RemoteIp> <Port>\n");
return 0;
}
// The Init Socket API.
nErr = WSAStartup(MAKEWORD(1,1),&wsaData);
assert(nErr==0);
nPort = (unsigned short)atol(argv[2]);
myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myOOBSocket!=INVALID_SOCKET);
myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myNormalSocket!=INVALID_SOCKET);
// Connect to the remote address.
remoteIp.sin_family = AF_INET;
remoteIp.sin_port = htons(nPort);;
remoteIp.sin_addr.S_un.S_addr = inet_addr(argv[1]);
nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
if (nErr == SOCKET_ERROR) {
printf("Connect failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}
nSize = send(myOOBSocket,"U",1, 0);
if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}
nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));
if (nErr == SOCKET_ERROR) {
int error = WSAGetLastError();
printf("Connect failed because of %lX\n", error);
goto Cleanup;
}
nSize = send(myNormalSocket, "N",1, 0);
if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
goto Cleanup;
}
printf("Read for input:\n");
for (;;) {
int ch = _getch();
_putch( ch );
if (ch=='.') {
shutdown(myOOBSocket, 2);
shutdown(myNormalSocket,2);
break;
}
char buf[10];
memset(buf, ch, sizeof(buf));
if (isupper(ch)) {
nSize = send(myOOBSocket, buf, sizeof(buf), 0);
}else{
nSize = send(myNormalSocket, buf, sizeof(buf), 0);
}
if (nSize == SOCKET_ERROR) {
printf("Send failed because of %lX\n", WSAGetLastError());
break;
}
}
Sleep(1000);
Cleanup:
if (myOOBSocket!=INVALID_SOCKET)
closesocket(myOOBSocket);
if (myNormalSocket!=INVALID_SOCKET)
closesocket(myNormalSocket);
WSACleanup();
return 0;
}
You must include a reference to the Winsock Library file, Ws2_32.lib, to make the code compile.
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <assert.h>
// Usage: myserver <port>
HANDLE hRecvEvent;
DWORD WINAPI OOBHandler(LPVOID lpParam)
{
int nErr, nRecv_len;
BYTE buffer[10 + 1];
BOOL bClosing=FALSE;
fd_set fdread;
SOCKET remoteSocket=(SOCKET)lpParam;
unsigned long ul=1;
int nRet = ioctlsocket(remoteSocket, FIONBIO, &ul);
if(SOCKET_ERROR==nRet){
printf("Socket() failed: %d\n", WSAGetLastError());
return 1;
}
printf("Waiting");
for (int i=0; i<10; i++) {
printf(".");
Sleep(1000);
}
printf("The OOB handler is ready!\n");
while (!bClosing){
//Always clear the set before you call the select method.
FD_ZERO(&fdread);
//Add sockets to the sets.
FD_SET(remoteSocket, &fdread);
nErr=select(0,&fdread,0,0,0);
if(nErr==SOCKET_ERROR)
{
printf("Select() failed: %d\n",WSAGetLastError());
return 1;
}
if(FD_ISSET(remoteSocket,&fdread)){
ResetEvent(hRecvEvent);
while(1)
{
nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
if(nRecv_len==0){
bClosing=TRUE;
printf("The connection is closed!\n");
break;
}
buffer[nRecv_len] = '\0';
printf("[OOB]: %s\n", buffer);
nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);
if (nRecv_len==SOCKET_ERROR) {
if(WSAGetLastError()==WSAEWOULDBLOCK)
break;
else
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
}
}
SetEvent(hRecvEvent);
}
}
return 0;
}
DWORD WINAPI NormalHandler(LPVOID lpParam)
{
int nErr,nRecv_len;
BYTE buffer[10 + 1];
fd_set fdread;
SOCKET remoteSocket=(SOCKET)lpParam;
printf("Waiting");
for (int i=0; i<10; i++) {
printf("*");
Sleep(1000);
}
printf("Normal handler ready!\n");
while(1) {
//Always clear the set before you call the select method.
FD_ZERO(&fdread);
//Add sockets to the sets.
FD_SET(remoteSocket, &fdread);
nErr=select(0,&fdread,0,0,0);
if(nErr==SOCKET_ERROR){
printf("Select() failed: %d\n",WSAGetLastError());
return 1;
}
if(FD_ISSET(remoteSocket,&fdread)){
WaitForSingleObject(hRecvEvent,INFINITE);
nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
if (nRecv_len==SOCKET_ERROR) {
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
return 1;
}
if(nRecv_len==0){
printf("Connection Closed!\n");
break;
}
buffer[nRecv_len] = '\0';
printf("[Normal]: %s\n", buffer);
}
}
return 0;
}
int main(int argc, char *argv[])
{
WSADATA wsaData;
int nErr;
SOCKET myListener = INVALID_SOCKET;
struct sockaddr_in localIp;
unsigned short nPort;
DWORD dwThreadId;
HANDLE hThread=NULL;
if (argc!=2)
{
printf("MyServer <Port>\n");
return 0;
}
nPort = (unsigned short)atol(argv[1]);
nErr = WSAStartup(MAKEWORD(2,0),&wsaData);
assert(nErr==0);
assert(wsaData.wVersion == MAKEWORD(2,0));
myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
assert(myListener!=INVALID_SOCKET);
// Bind the listen socket to any local IP address.
localIp.sin_family = AF_INET;
localIp.sin_port = htons(nPort);;
localIp.sin_addr.S_un.S_addr = INADDR_ANY;
nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));
assert(nErr!=SOCKET_ERROR);
nErr = listen(myListener, 5);
assert(nErr==0);
//Create a manual-reset event object.
hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
if (hRecvEvent == NULL)
{
printf("CreateEvent failed with error 0x%lx\n", GetLastError());
return 1;
}
printf("The server is ready!\n");
for (;;) {
struct sockaddr_in remoteIp;
SOCKET remoteSocket = INVALID_SOCKET;
int nAddrLen = sizeof(SOCKADDR);
remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);
if(remoteSocket == INVALID_SOCKET) {
int error = WSAGetLastError();
printf("Accept() failed. Win32 error is 0x%lx\n", GetLastError());
goto Cleanup;
} else {
printf("Connected from %d.%d.%d.%d:%d\n",
remoteIp.sin_addr.S_un.S_un_b.s_b1,
remoteIp.sin_addr.S_un.S_un_b.s_b2,
remoteIp.sin_addr.S_un.S_un_b.s_b3,
remoteIp.sin_addr.S_un.S_un_b.s_b4,
ntohs(remoteIp.sin_port));
BYTE buffer[1+1];
int nRecv_len=recv(remoteSocket,(char *)&buffer,1,0);
if (nRecv_len==SOCKET_ERROR) {
printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());
return 1;
}
buffer[nRecv_len] = '\0';
if(strcmp((char *)buffer,"U")==0)
hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);
else if(strcmp((char *)buffer,"N")==0)
hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);
if(hThread==0){
printf("CreateThread() failed: %d\n",GetLastError());
return 1;
}
CloseHandle(hThread);
}
}
closesocket(myListener);
Cleanup:
WSACleanup();
return 0;
}