Preliminary Winsock programming principles
This course focuses on the TCP/IP programming interface Winsock in Windows. The version is 1.1. The later version of Winsock is similar to that of Version 1.1. It mainly involves some extensions, such as using sockets to implement IPX, NETBIOS, and other communication protocols beyond the TCP/IP protocol.
Winsock mentioned in the rest of this Article refers to Winsock1.1.
Through Winsock, point-to-point or broadcast communication programs can be implemented. In reality, there is little difference between the two. During programming, the code used in the program process is almost the same. The difference lies in the selection of the target address. The instances used in this course are in the form of point-to-point communication, and build point-to-point communication through Winsock in the form of customer/Server, and name the two points in the communication process as Server and Client respectively.
In order to clearly describe the Winsock structure and principles, the following describes the general telephone service of the Telecommunications Bureau as a comparison object:
1. The Telecommunications Bureau provides telephone services similar to the Server provided by moderators, while ordinary telephone users are similar to clients provided by moderators.
2. First, the Telecommunications Bureau must establish a telephone switchboard. Therefore, if the moderators must establish a Socket on the Server, this step is implemented by calling the socket () function.
3. The Telecommunications Bureau must assign a phone number to the telephone switchboard so that the user can call the phone number to obtain the telephone service. At the same time, the user accessing the telephone bureau must know the phone number of the telephone switchboard. Similarly, the moderator must specify a port for the socket on the Server side, and the Client connecting to the Server must know the port. This step is implemented by calling the bind () function.
4. Next, the Telecommunications Bureau must enable the switchboard and enable the switchboard to efficiently monitor user dialing. If the Telecommunications Bureau provides too many users of services, you will find that the switchboard is always busy, generally, the Telecommunications Bureau connects the phone number of the switchboard to several exchange processing centers. When a processing center is busy processing a user, new users can automatically go to the processing center to get the service. Similarly, the Server end of the moderators must set their own interfaces to the listening status. This is implemented by the General listen () function. The second parameter of listen () is the number of waiting queues, just as you can designate a Telecommunications Bureau to establish several exchange processing centers.
5. the user can make a call request to get the service after knowing the telephone number of the Telecommunications Bureau. In the Winsock world, as a Client, you need to first use the socket () function to establish a socket, and then call the connect () function to connect. Of course, the connection will not succeed if the number of waiting queues is full, the connection is disconnected from the Server, or the Server does not provide this service.
5. After receiving the call, the carrier's switchboard is responsible for connecting the user's line, and the switchboard itself returns to the waiting state. The same is true for the Server. When the accept () function is called to process the listener, the Server code is paused in the middle, once the Server receives the application, the system will establish a new socket to serve the connection, and the original socket will return to the waiting status of the listener.
6. When your phone is finished, you can hook up the phone and connect them offline. The same is true for the socket close between the Client and the Server. The offline close action can be performed by the Client or Server to persuade the sister-in-law to close it first. Isn't the same for some telephone query systems? The function for disabling the socket is
Closesocket ().
From the above situation, we can see that the process of creating a socket on the server and entering the actual listening steps is as follows: socket ()-> bind ()-> listen ()-> accept ()
After accept () is complete, the moderators say that a new socket will be generated on the Server side, and the Server will continue to enter the accept () status, how can moderators use this new socket to communicate with the Client? This uses the recv () function, while the Client uses the send () function to send messages to the server.
A similar process is also adopted on the client. The process of calling Winsock is as follows:
Socket ()-> connect ()-> send ()
First, establish a socket and connect it to the socket on the Server using the connect () function. After the connection is successful, send () is called to send the message.
// A simplest web server
// Written by Shen zhiliang for learning Winsock & HTTP
File: // zhiliang@sina.com
# Include "winsock. h"
# Include "stdio. h"
# Include "conio. h"
# Include "io. h"
# Define BUFLEN 2048
# Define DEFPATH ("C: // frontpage webs // content //")
# Define DEFFILE ("INDEX. HTM ")
# Define HTTPHEAD ("HTTP/1.0 200 OK/010 Date: Monday, 04-Jan-99 17:06:17 GMT/x0aServer: HTTP-Server/1.0/x0a MIME-version: 1.0/x0a ")
# Define MIMEHTML ("Content-type: text/html/x0a Last-modified: Friday, 26-Sep-97 09:36:54 GMT/x0a ")
# Define MIMEGIF ("Content-type:/image/gif/x0a Last-modified: Friday, 26-Sep-97 09:36:54 GMT/x0a ")
# Define MIMEJPEG ("Content-type:/image/jpeg/x0a Last-modified: Friday, 26-Sep-97 09:36:54 GMT/x0a ")
# Define MIMEPAIN ("Content-type: text/pain/x0a Last-modified: Friday, 26-Sep-97 09:36:54 GMT/x0a ")
# Define HTMLHEAD ("# Define HTMLTAIL ("/n </body>
Void P (char *)
{
Printf ("Error in: % s/n", );
}
/*
Char * httphead (FILE * fp)
{
Struct tm * newtime;
Time_t aclock;
Time (& aclock );
Newtime = localtime (& aclock );
Printf ("The current date and time are: % s", asctime (newtime ));
}
*/
Void HtmlError (SOCKET s, unsigned int code, char * msg)
{
Char tmp [1024];
Sprintf (tmp, "Error code: % d % s", code, msg );
Send (s, HTTPHEAD, strlen (HTTPHEAD), 0 );
Send (s, HTMLHEAD, strlen (HTMLHEAD), 0 );
Send (s, tmp, strlen (tmp), 0 );
Send (s, HTMLTAIL, strlen (HTMLTAIL), 0 );
}
Void SendHtmlFile (SOCKET s, char * filename)
{
FILE * fp;
Char * tmp;
Char fullname [512];
Char buf [1024];
Int I;
Strcpy (fullname, DEFPATH );
If (strlen (filename) = 0 | (strlen (filename) = 1 & filename [0] = '/'))
Strcat (fullname, DEFFILE );
Else
{
Do {
Tmp = strchr (filename ,'/');
If (tmp! = NULL)
Tmp [0] = '//';
} While (tmp! = NULL );
If (filename [0] = '//')
Strcat (fullname, & filename [1]);
Else
Strcat (fullname, filename );
}
FILE * fpt = fopen ("recv. dat", "a + B ");
Fwrite (fullname, sizeof (char), strlen (fullname), fpt );
Fclose (fpt );
Fp = fopen (fullname, "rb ");
If (fp = NULL)
{
Char msg [512];
If (filename [0] = '//')
Filename [0] = '/';
Sprintf (msg, "URI no found: % s", filename );
HtmlError (s, 404, msg );
Return;
}
Send (s, HTTPHEAD, strlen (HTTPHEAD), 0 );
If (stricmp (& filename [strlen (filename)-4], ". GIF") = 0)
Send (s, MIMEGIF, strlen (MIMEGIF), 0 );
Else if (stricmp (& filename [strlen (filename)-4], ". JPG ") = 0 | stricmp (& filename [strlen (filename)-5],". JPEG ") = 0)
Send (s, MIMEJPEG, strlen (MIMEJPEG), 0 );
Else if (stricmp (& filename [strlen (filename)-4], ". HTM ") = 0 | stricmp (& filename [strlen (filename)-5],". HTML ") = 0)
{
Send (s, MIMEHTML, strlen (MIMEHTML), 0 );
}
Long fs = _ filelength (_ fileno (fp ));
Buf [0] = 0;
Sprintf (buf, "Content-length: % ld/x0a/x0a", fs );
Send (s, buf, strlen (buf), 0 );
For (I = 0 ;! Feof (fp); I ++)
{
Buf [I] = fgetc (fp );
If (I> = 1023 | feof (fp ))
{
Send (s, buf, I, 0 );
I = 0;
}
}
Fclose (fp );
}
Void SocketError (char * call)
{
Fprintf (stderr, "WinSock Error # function: % s, error code: % ld/n", call, WSAGetLastError ());
}
Main (int argc, char ** argv)
{
Int iRes, iPort, iTmp;
SOCKET s, rs;
SOCKADDR_IN sin, rsin;
WSADATA wsad;
WORD wVersionReq;
Char recvBuf [BUFLEN];
If (argc <2)
{
Fprintf (stderr, "Usage: WebSphere server 999/n/t999-Port number for this server .");
Return-1;
}
IPort = 0;
IPort = atoi (argv [1]);
If (iPort <= 0)
{
Fprintf (stderr, "must specify a port number ");
Return-1;
}
WVersionReq = MAKEWORD (1, 1 );
IRes = WSAStartup (wVersionReq, & wsad );
If (iRes! = 0)
{
SocketError ("WSAStartup ()");
Return-1;
}
S = socket (PF_INET, SOCK_STREAM, 0 );
If (s = INVALID_SOCKET)
{
SocketError ("socket ()");
Return-1;
}
Sin. sin_family = PF_INET;
Sin. sin_port = htons (iPort );
Sin. sin_addr.s_addr = INADDR_ANY;
ITmp = sizeof (sin );
If (bind (s, (LPSOCKADDR) & sin, iTmp) = SOCKET_ERROR)
{
SocketError ("bind ()");
Closesocket (s );
WSACleanup ();
Return-1;
}
If (listen (s, 1) = SOCKET_ERROR)
{
SocketError ("listen ()");
Closesocket (s );
WSACleanup ();
Return-1;
}
Fprintf (stderr, "WebServer Running.../n ");
ITmp = sizeof (rsin );
Rs = 0;
While (1)
{
If (_ kbhit ()! = 0)
{
If (_ getch ()! = 27)
Break;
If (rc! = 0)
Closesocket (rs );
Closesocket (s );
WSACleanup ();
Fprintf (stderr, "WebServer Stopped.../n ");
Return 0;
}
Rs = accept (s, (LPSOCKADDR) & rsin, & iTmp );
If (rs = INVALID_SOCKET)
{
Socketerror ("accept ()");
Closesocket (s );
Wsacleanup ();
Return-1;
}
IRES = Recv (RS, recvbuf, buflen, 0 );
Printf ("received data:/n ---------------------------------/n % s/n -----------------------------------/N", recvbuf );
If (IRES = socket_error)
{
Socketerror ("Recv ()");
Closesocket (rs );
Closesocket (s );
WSACleanup ();
Return-1;
}
Char * sRes;
SRes = strstr (recvBuf, "GET ");
If (sRes! = NULL & (sRes-recvBuf) <3)
SRes = strchr (recvBuf ,'/');
If (sRes! = NULL)
{
Char * sRes1;
SRes1 = strchr (sRes, '/R ');
If (strchr (sRes, '') <sRes1)
SRes1 = strchr (sRes ,'');
If (sRes1! = NULL & (sRes1-sRes) <256)
{
Char tmp [256];
Strncpy (tmp, sRes, (sRes1-sRes ));
Tmp [sRes1-sRes] = 0;
Int I;
For (I = strlen (tmp)-1; (tmp [I] = ''| tmp [I] = '/t') & I> = 0; I --)
Tmp [I] = 0;
For (I = 0; tmp [I] = ''| tmp [I] = '/T'; I ++ );
SendHtmlFile (rs, & tmp [I]);
}
}
Else
{
Htmlerror (RS, 202, "Bad request ");
}
Closesocket (RS );
}
Return 0;
}
// A simplest Web Client
// Written by Shen zhiliang for learning Winsock & HTTP
// Zhiliang@sina.com
// 1998.7.29
# Include "Winsock. H"
# Include "stdio. H"
# Define buflen 4096
Void socketerror (char * call)
{
Fprintf (stderr, "Winsock Error # function: % s, error code: % LD/N", call, wsagetlasterror ());
}
Main (int argc, char ** argv)
{
Int iRes, iPort, iTmp;
SOCKET s, rs;
SOCKADDR_IN sin, rsin;
WSADATA wsad;
WORD wVersionReq;
Char recvBuf [BUFLEN];
If (argc <4)
{
Fprintf (stderr, "Usage: sockserver ip port message/n ");
Return-1;
}
If (inet_addr (argv [1]) = INADDR_NONE)
{
Fprintf (stderr, "Error ip gaving/n ");
Return-1;
}
IPort = 0;
IPort = atoi (argv [2]);
Sin. sin_addr.s_addr = inet_addr (argv [1]);
Sin. sin_family = PF_INET;
Sin. sin_port = htons (iPort );
If (iPort <= 0)
{
Fprintf (stderr, "must specify a number for port/n ");
Return-1;
}
WVersionReq = MAKEWORD (1, 1 );
IRes = WSAStartup (wVersionReq, & wsad );
If (iRes! = 0)
{
SocketError ("WSAStartup ()");
Return-1;
}
S = socket (PF_INET, SOCK_STREAM, 0 );
If (s = INVALID_SOCKET)
{
SocketError ("socket ()");
Return-1;
}
ITmp = sizeof (sin );
Fprintf (stderr, "WinSock Client Start.../n ");
If (connect (s, (LPSOCKADDR) & sin, iTmp) = SOCKET_ERROR)
{
SocketError ("connect ()");
Closesocket (s );
WSACleanup ();
Return-1;
}
Strcpy (recvBuf, argv [3]);
Strcat (recvBuf, "/r/n ");
IRes = send (s, recvBuf, strlen (recvBuf), 0 );
If (iRes = SOCKET_ERROR)
{
SocketError ("send ()");
Closesocket (s );
WSACleanup ();
Return-1;
}
Printf ("Sent Data:/n ------------------/n % s/n ------------------/n", recvBuf );
FILE * fp = fopen ("send. dat", "a + B ");
If (fp = NULL)
Return-1;
IRES = Recv (S, recvbuf, buflen, 0 );
While (IRES! = Socket_error & IRES! = 0)
{
Printf ("received data:/n ------------------/n % s/n ------------------/N", recvbuf );
Fwrite (recvbuf, sizeof (char), IRES, FP );
IRES = Recv (S, recvbuf, buflen, 0 );
}
Fclose (FP );
Closesocket (s );
Wsacleanup ();
Return 0;
}
Winsock function usage instructions
Wsastartup ()
Link the application to the first function of WinSock. dll.
Format:
Int WSAStartup (WORD wVersionRequested, LPWSADATA lpWSAData)
Parameters:
Windows Sockets API version to be used by wVersionRequested
LpWSAData indicators pointing to WSADATA
Return Value:
Success-0
Failed-WSASYSNOTREADY/WSAVERNOTSUPPORTED/WSAEINVAL
Note:
This function must be called by the application to call the first function in the Windows Sockets DLL function before calling other Windows Sockets DLL functions. This function allows you to specify the version of the Windows Sockets API to be used and obtain information about the designer.
Socket ()
Create a Socket.
Format:
SOCKET socket (int af, int type, int protocol)
Parameters:
Af currently only provides PF_INET (AF_INET)
Type Socket type (SOCK_STREAM, SOCK_DGRAM)
Protocol Communication protocol (set to 0 if not specified by the user)
Return Value:
Success-Socket identifier
Failed-INVALID_SOCKET (call WSAGetLastError () to find the cause)
Note:
This function is used to establish a socket and establish the resources used by the socket. The socket type can be stream socket or datemedisocket.
BIND ()
Specifies the local address (address) of the socket ).
Format:
Int BIND (socket S, const struct sockaddr far * Name, int namelen );
Parameters:
S socket identifier
Name socket address value
Namelen Name Length
Return Value:
Success-0
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
This function specifies the local address and port to a socket with an unknown name. If the user does not care about the address or port value, he can set the address to inaddr_any and port to 0; then, Windows Sockets automatically sets the appropriate address and port (value between 1024 and 5000). After the socket is actually connected, the user can call getsockname () to obtain the set value.
The BIND () function must specify the address and port. The address must be the IP address of the machine on which the program is executed. Therefore, if you design a program, you can set the address to inaddr_any, in this way, the Winsock system automatically fills in the correct address of the machine. If you want the program to run on only one machine, set the IP address to the IP address of the machine. Because this end is the server end, the moderators must specify a port number for this socket.
Listen ()
Set the socket to the listening status and prepare to be connected.
Format:
Int listen (socket S, int backlog );
Parameters:
S socket identifier
Maximum number of connections required for a backlog before the connection is completed (before the accept is called)
Return Value:
Success-0
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
You can use this function to set the socket to enter the listening status, and set the maximum number of connection requirements for each end before the connection is completed. (Currently, the maximum value is 5 and the minimum value is 1)
Connect ()
A tcp socket must be connected to the specified peer.
Format:
Int connect (socket S, const struct sockaddr far * Name, int namelen );
Parameters:
S socket identifier
Name the target address of the socket
Namelen Name Length
Return Value:
Success-0
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
This function is used to request the other party to establish a connection. If the specified peer address is 0, an error value is returned. After the connection is established, the user can use this socket to send or receive data.
Accept ()
Accept the connection requirements of a socket to complete the connection of stream socket.
Format:
Socket accept (scoket S, sockaddr * ADDR, int far * addrlen)
Parameters:
S socket identifier
ADDR stores the address of the peer connection
Length of addrlen ADDR
Return Value:
Success-new socket identifier
Failed-invalid_socket (call wsagetlasterror () to find the cause)
Note:
Server applications call this function to accept socket connection requests required by the client.
Closesocket ()
Close a socket.
Format:
Int closesocket (socket S );
Parameters:
S socket identifier
Return Value:
Success-0
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
This function is used to close a socket.
Wsacleanup ()
End the use of Windows Sockets DLL.
Format:
Int wsacleanup (void );
Parameter count: None
Return Value:
Success-0
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
When an application no longer needs Windows Sockets DLL, you must call this function to cancel use to release the resources it occupies.
Send ()
Use a connector socket to send data.
Format:
Int send (socket S, const char far * Buf, int Len, int flags );
Parameters:
S socket identifier
Buf is the temporary storage area for storing the data to be transferred.
Len Buf Length
Flags: How this function is called
Return Value:
Success-length of the sent data
Failure-socket_error (call wsagetlasterror () to learn the cause)
Note:
This function is used to send information from the local end to the remote end through socket.
Recv ()
Receive data from socket.
Format:
Int recv (SOCKET s, char FAR * buf, int len, int flags );
Parameters:
S Socket identifier
The temporary storage area where the buf stores the received data
Len buf Length
Flags: How this function is called
Return Value:
Success-length of received data (0 if the Socket of the other party is disabled)
Failure-SOCKET_ERROR (call WSAGetLastError () to learn the cause)
Note:
This function receives data using a connected datasync Socket or Stream Socket. For Stream Socket, moderators can receive valid data in the current input buffer, but the number of data files cannot exceed the len size.
WSAStartup ()
Connect the application to the first function of Windows Sockets DLL.
Format:
Int WSAStartup (WORD wVersionRequested, LPWSADATA lpWSAData );
Parameters:
Maximum Windows Sockets API version available for wVersionRequested
LpWSAData indicators pointing to WSADATA
Return Value:
Success-0
Failed-WSASYSNOTREADY/WSAVERNOTSUPPORTED/WSAEINVAL
Note:
This function "must" is the first function that the application calls to the Windows Sockets DLL function. Only after the call is successful can other Windows Sockets DLL functions be called. This function allows you to specify the version of the Windows Sockets API to be used and obtain information about the designer.