Use TCP to provide sequenced, reliable two-way connection-based byte streams. A TCP stream socket server application listens on the network for incoming client request packets. A TCP stream socket client application initiates communication with the server by sending a request packet. When the server receives the request, it processes it and responds. After this initial sequenced message exchange, client and server can exchange data. The following illustration shows the interaction between the TCP stream socket server and TCP stream socket client.
Use AF_INET for the address format parameter and SOCK_STREAM for the type parameter.
The following code example shows how to open a socket.
if ((WinSocket = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
When you open a socket with socket, the socket has no name assigned to it. However, a descriptor for the socket is allocated in an address family name space. To assign a name to the server socket, call bind. To be identified by the client socket, a TCP stream socket server application must name its socket. However, it is unnecessary to give a client socket a name, using bind.
The bind function establishes the local socket association by assigning a local socket name to an unnamed socket. A socket name consists of three address fields when in the TCP/IP address family, known as the Internet address family: the address family protocol, a host address, and a port number that identifies the application. These address fields, sin_family, sin_addr, sin_port, are members of the SOCKADDR_IN structure. You must initialize SOCKADDR_IN before calling bind.
The following code example shows how to initialize SOCKADDR_IN, and then use bind.
// Fill out the local socket address data.
local_sin.sin_family = AF_INET;
local_sin.sin_port = htons (PORTNUM);
local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
// Associate the local address with WinSocket.
if (bind (WinSocket,
(struct sockaddr *) &local_sin,
sizeof (local_sin)) == SOCKET_ERROR)
{
wsprintf (szError, TEXT("Binding socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
To prepare for a name association the TCP stream server must first listen for connection requests from the TCP client with the listen function.
The following code example shows how to use listen.
if (listen (WinSocket, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Listening to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
The TCP stream server socket uses accept to accept the client connection that completes the name association between client and server.
The accept function creates a new socket. The original socket opened by the server continues to listen and can be used to accept more connections until closed. Server applications must close the listening socket, in addition to any sockets created, by accepting a client connection.
The following code example shows how to use accept.
accept_sin_len = sizeof (accept_sin);
// Accept an incoming connection attempt on WinSocket.
ClientSock = accept (WinSocket,
(struct sockaddr *) &accept_sin,
(int *) &accept_sin_len);
// Stop listening for connections from clients.
closesocket (WinSocket);
if (ClientSock == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Accepting connection with client
failed.") TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
Once client and server sockets are connected, you can use the send and recv functions to exchange data.
The send function writes outgoing data on a connected socket. The recv function reads incoming data on connection-oriented sockets. The recv function can also be used with connectionless sockets. When using a TCP connection-oriented stream, a socket must be connected before calling recv.
The following code shows an example of using the send and recv functions.
for (;;)
{
// Receive data from the client.
iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);
// Verify that data was received. If yes, display it.
if (iReturn == SOCKET_ERROR)
{
wsprintf (szError, TEXT("No data is received, receive failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Server"), MB_OK);
break;
}
else if (iReturn == 0)
{
MessageBox (NULL, TEXT("Finished receiving data"),
TEXT("Server"), MB_OK);
break;
}
else
{
// Convert the ASCII string to Unicode.
for (index = 0; index <= sizeof (szServerA); index++)
szServerW[index] = szServerA[index];
// Display the string received from the client.
MessageBox (NULL, szServerW, TEXT("Received From Client"),
MB_OK);
}
}
// Send a string from the server to the client.
if (send (ClientSock, "To Client.", strlen ("To Client.") + 1, 0)
== SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Sending data to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
Successfully completing a call to send does not confirm that data was successfully delivered.
When data exchange between the server and client ends, close the socket with closesocket. To ensure that all data is exchanged on a TCP connection, an application should call shutdown before calling closesocket.
An application should always have a matching call to closesocket for each successful call to socket to return any socket resources to the system. For TCP stream sockets, when a socket connection ends the server closes the socket created by accept. The server does not close the socket originally returned by the first call to socket. That socket continues to listen for clients. When the server disconnects or is out of service it should call closesocket to close the listening socket.
For an example of a TCP stream socket server application, see TCP Stream Socket Server.
Use AF_INET for the address format parameter and SOCK_STREAM for the type parameter.
The TCP stream client associates socket names by connecting to the stream server with connect.
The SOCKADDR_IN structure must be initialized before calling connect. This is similar to using bind, but sin_port and sin_addr are initialized with the remote socket name, not the local socket name used for bind.
The following code example shows the TCP client connecting with the server.
// Establish a connection to the server socket.
if (connect (ServerSock,
(PSOCKADDR) &destination_sin,
sizeof (destination_sin)) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Connecting to the server failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (ServerSock);
return FALSE;
}
For an example of a TCP stream socket client application, see TCP Stream Socket Client.