Winsock Programming Blocking and Asynchronous Sockets for Windows.

23
Winsock Programming Winsock Programming Blocking and Asynchronous Blocking and Asynchronous Sockets for Windows Sockets for Windows

Transcript of Winsock Programming Blocking and Asynchronous Sockets for Windows.

Page 1: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Winsock ProgrammingWinsock Programming

Blocking and Asynchronous Blocking and Asynchronous Sockets for WindowsSockets for Windows

Page 2: Winsock Programming Blocking and Asynchronous Sockets for Windows.

HistoryHistory

• MS-DOS/Windows not designed for networking

• Early Microsoft operating systems ignored the TCP/IP stack

• “Visionary” Bill Gates supports NETBIOS over TCP/IP• Several packages offered by 3rd parties• “Trumpet Winsock”• None work particularly well

Page 3: Winsock Programming Blocking and Asynchronous Sockets for Windows.

What is Winsock?What is Winsock?

• API, SPI and ABI– API for application developers– SPI for network software vendors– ABI to ensure consistent interoperability

between applications and various implementations of Winsock

• Less important now that Microsoft has released a quality Winsock– No significant alternatives

Page 4: Winsock Programming Blocking and Asynchronous Sockets for Windows.

The APIThe API

• Based on BSD sockets API– First of many Microsoft “hacks”

• Complications due to differences between Unix and Windows– errno (Unix) vs. WSAGetLastError()– BSD sockets based on C and Unix

• fork()• File descriptors

Page 5: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Example: The Unix WayExample: The Unix Waywhile (1) {

newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

if (newsockfd < 0) error("ERROR on accept");

pid = fork();

if (pid < 0) error("ERROR on fork");

if (pid == 0) { close(sockfd); dostuff(newsockfd); exit(0); }

else close(newsockfd);

}

Page 6: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Steps to a Listen SocketSteps to a Listen Socket

• Initialize Winsock• Fill out SOCKADDR_IN (define the socket)• Create the socket• bind() the socket• Make the socket listen()• Wait on accept()• Handle clients via socket returned by

accept()

Page 7: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Example: Listening (simplified)Example: Listening (simplified)// INITIALIZEsockVersion = MAKEWORD(1, 1); // Winsock version 1.1 WSAStartup(sockVersion, &wsaData);

// CREATE SOCKETSOCKET listeningSocket; listeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// DEFINE SOCKETSOCKADDR_IN serverInfo; serverInfo.sin_family = AF_INET; serverInfo.sin_addr.s_addr = INADDR_ANY; serverInfo.sin_port = htons(8888);

// BINDbind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));

// LISTENlisten(listeningSocket, 10);

// ACCEPTSOCKET theClient; theClient = accept(listeningSocket, NULL, NULL);

Page 8: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Steps to ConnectingSteps to Connecting

• Initialize Winsock

• Fill out HOSTENT

• Create socket

• Fill out SOCKADDR_IN

• Connect

• Send/recv

Page 9: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Example: Connecting (simplified)Example: Connecting (simplified)

// INITIALIZEsockVersion = MAKEWORD(1, 1); WSAStartup(sockVersion, &wsaData);

// FILL OUT HOSTENTLPHOSTENT hostEntry = gethostbyname("www.hal-pc.org");

// CREATE SOCKETSOCKET theSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

// FILL OUT SOCKADDR_INSOCKADDR_IN serverInfo; serverInfo.sin_family = AF_INET; serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list); serverInfo.sin_port = htons(80);

// CONNECTconnect(theSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));

Page 10: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Sending and ReceivingSending and Receiving

• int send(SOCKET s, char * buf, int len, int flags);– Returns number of bytes sent or

SOCKET_ERROR• int recv(SOCKET s, char * buf, int len, int flags);

– Returns number of bytes received or SOCKET_ERROR

• Send and recv must be done in loops to ensure all data is sent/received

Page 11: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Problem: blockingProblem: blocking

• Many of these functions “block”– accept()– connect()– send()– recv()

• One solution: poll sockets using select()

• Another solution: threads

• Coolest solution: asynchronous sockets

Page 12: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Why Asynchronous?Why Asynchronous?

• Windows handles polling for you

• Familiar Windows message paradigm

• Easy to read code

Page 13: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Why Why NOTNOT Asynchronous? Asynchronous?

• Non-portable

• Microsoft is evil

• Use them anyways, they are cool

Page 14: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Windows MessagesWindows Messages

• Message queue

• Message pump– “first chance” message handling

• Message Handler– Callback function

Page 15: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Sample Message PumpSample Message PumpHRESULT hRet; UINT Msg;

while( (hRet = GetMessage( &Msg, NULL, 0, 0 )) != 0) {    if (hRet == -1) {       PostQuitMessage(1);    }    else    {       TranslateMessage(&Msg);       DispatchMessage(&Msg);    } }

Page 16: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Sample Message HandlerSample Message HandlerLRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_DESTROY:

PostQuitMessage(WM_QUIT); break; default: return FALSE; } return TRUE; }

Page 17: Winsock Programming Blocking and Asynchronous Sockets for Windows.

How Does This Apply?How Does This Apply?

• Windows sends messages when sockets are waiting– No need to poll– No need for many threads– Create sockets and go about other tasks– Handle sockets just like any other Windows

control

Page 18: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Making a socket asynchronousMaking a socket asynchronous

int PASCAL WSAAsyncSelect( SOCKET s,

HWND hwnd,

unsigned int Msg,

long event

);

Simple call to WSAAsyncSelect:

Page 19: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Message and EventsMessage and Events

• Five events:– FD_READ

– FD_WRITE

– FD_CONNECT

– FD_ACCEPT

– FD_CLOSE

– OR these together to tell Windows what notifications you need

• User defined messages– WM_USER + n

Page 20: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Handling the messageHandling the message

• wParam: – socket instance

• lParam:– HIWORD:

• 0 (success)• Error code

– LOWORD:• FD_READ, FD_WRITE, etc.

Page 21: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Example: Handling FD_ACCEPTExample: Handling FD_ACCEPT

SOCKET s;

switch (msg) { case WM_USER + 5: switch(WSAGETSELECTEVENT(lParam) { case FD_ACCEPT: s = accept(wParam, NULL, NULL); break; } break;}

Page 22: Winsock Programming Blocking and Asynchronous Sockets for Windows.

SummarySummary

• Why this is important:– Current Winsock responsible for increase in

quantity and popularity of Internet applications– Almost all applications use the Internet

somehow, or could be improved by using the Internet

Page 23: Winsock Programming Blocking and Asynchronous Sockets for Windows.

Example: Version CheckingExample: Version Checking

DWORD WINAPI CGlowdotChatServer::DoVersionCheckThreadProc(LPVOID pvoid) {

struct sockaddr_in sa; struct hostent *hp;

hp = gethostbyname(“www.stromcode.com”);

memset(&sa,0,sizeof(sa));

// set address and portmemcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; sa.sin_port = htons((u_short)VERSION_CHECK_PORT);

// create socketSOCKET s = socket(hp->h_addrtype, SOCK_STREAM, 0);

std::string request ("GET /glowdotchat/server/checkversion.php?getcurrentversion=yes HTTP/1.1\nUser-Agent:Mozilla\nHost:www.stromcode.com\n\n");

send(s, request.c_str(), request.length(),0);

char buf[1000];std::string response("");

recv(s, buf, 1000, 0);response += std::string(buf);

std::string::size_type pos1 = response.find(std::string("<current-version>"));std::string::size_type pos2 = response.find(std::string("</current-version>"));

response = response.substr(pos1 + 17, pos2 - pos1 - 17);

if (response == std::string(VERSION)) {// server up to date

} else {// new version available

}

return 0;}