Basic introduction to the development of BSD socket interface in Linux _unix Linux

Source: Internet
Author: User
Tags htons

This is the first of a series of articles on how to develop Web programs for Linux using a variety of available interfaces. Like most unix-based operating systems, Linux supports the use of TCP/IP as a local network transport protocol. In this series, we assume that you are familiar with C programming on Linux and some of Linux's system knowledge such as signals,forking and so on.


This article is a basic introduction to how to create a network program with a BSD set of interfaces. In the next article, we will address the issue of establishing a (network) Deamon process. And in future articles we will also involve using remote procedure calls (RPC) and developing them with corba/distributed objects.

First, the basic introduction of TCP/IP

The TCP/IP protocol family allows two of programs running on the same computer or two computers connected by the network to communicate. This protocol family is designed specifically to communicate on unreliable networks. TCP/IP allows two basic operating modes-connection-oriented reliable transmission (referring to TCP) and connectionless (connectionless) unreliable transport (UDP).

TCP provides a sequential, reliable, two-way (bi-directional), concatenated, byte transport stream with a transparent relay function to the upper layer protocol. TCP divides your information into datagrams (no more than 64KB) and ensures that all the datagrams arrive at their destinations in order. Because a connection is based, a virtual connection must be established before a network entity (network entity) communicates with another. UDP, on the other hand, provides a (very fast) connectionless, unreachable message transmission (the size of the message is a determined maximum length).

To allow programs to communicate with each other, whether they are on the same machine (via the loopback interface) or different hosts, each program must have a separate address.

The TCP/IP address is made up of two parts--used to identify the machine's IP address and the port address used to identify the particular program on that machine.

The address can be a dotted (dotted-quad) symbolic form (e.g., 127.0.0.1) or a host name (e.g., www.csdn.net). The system can use the/etc/hosts or DNS domain Name service (if available) to convert the host name to the symbolic address (that is, the IP address).

The port is numbered starting from number 1th. The segment number between 1 and ipp0rt_reserved (defined in/usr/include/netinet/in.h, typically 1024) is reserved for system use (that is, you must establish a network service as root to bind this part of the port).

The most simple client-server model for most Web applications. A service process waits for a client process to connect to him. When a connection is established, the server performs a specific task on behalf of the client, usually after which the connection is interrupted.

Second, the use of the BSD interface interface


The most popular method of TCP/IP programming is to use the BSD interface interface programming. Through it, the network endpoint (network endpoints) (IP address and port address) appears as a nested interface (sockets).

This condom interface IPC (interprocess communication, interprocess communication) facility (introduced from 4.2BSD) is designed to allow the design of Web programs to be independent of the different underlying communication facilities.

1. Set up a server program

To create a server program using the BSD interface, you must use the following steps:

(1) Establish a socket interface via function socket ()
(2) Bind an address (IP address and port address) via a function bind (). This step determines the location of the server so that the client knows how to access it.
(3) A new connection request via function Listem () listener (listen) port.
(4) Accept the new connection through the function accept ().

Typically, maintenance represents a customer's request that can take a considerable amount of time. When processing a request, it should also be efficient to receive and process new requests. The most common way to achieve this is to have the server copy its own process through the fork () function to accept the new connection.

The following example shows how the server is implemented in C:

/*
* simple "Hello, world!" server
* Ivan Griffin

*/

/* Hellwolf Misty Translated * *

#include/* * *
#include/* EXIT () * *
#include/* memset (), memcpy () * *
#include/* uname () * *
#include
#include/* socket (), bind (),
Listen (), accept () * *
#include
#include
#include
#include/* fork (), write (), close () * *


/*
* Constants
*/
const char message[] = "Hello, world!\n";
const int back_log = 5;

/*

The


* program requires a command-line argument: the port number that needs to be bound
 */
int main (int argc, char *argv[])
{
int serversocket = 0,
on = 0  ,
Port = 0,
Status = 0,
childpid = 0;
struct Hostent *hostptr = NULL;
Char hostname[80] = "";
struct sockaddr_in serverName = {0};


if (2!= argc)
{
fprintf (stderr, Usage:%s \ n,
  argv[0]);
Exit (1);
}
Port = atoi (argv[1]);
/*
  *socket () system call with three parameters:
  * 1, parameter domain indicates the communication domain, such as Pf_unix (UNIX domain), pf_inet (IPV4),
  * pf_inet 6 (IPV6)
  * 2, type indicates the type of communication, most commonly used such as sock_stream (connection-oriented reliable, 
  * such as TCP), SOCK_DGRAM (non-connection-oriented, unreliable methods such as UD P) and so on.
  * 3, parameter protocol specifies the protocol to use. Although you can specify different protocol
  * parameters for the same protocol
  * Family (protocol family) (or domain), there is usually only one. The TCP parameter can be specified as IPPROTO_TCP and IPPROTO_UDP can be used for
  * UDP.   You do not have to explicitly set this parameter, use 0 to use the default protocol based on the previous
  * two parameters.  
  */ 
ServerSocket = socket (pf_inet, sock_stream,
  ipproto_tcp);
    if ( -1 = = ServerSocket)
{
Perror ("socket ()");
Exit (1);   
}

/*
* Once the socket is established, its operating mechanism can be modified by the socket option.
*/

/*
* The setting of the SO_REUSEADDR option sets the socket interface to reuse the old address (IP address plus port number) without waiting
* Note: In a Linux system, if a socket is bound to a port, the socket shuts down properly or the program exits,
* The port remains bound for a period of time, and other programs (or the original program that was restarted) cannot bind to the port.
*
* In the following call: Sol_socket represents the operation of the socket layer
*/
on = 1;

Status = SetSockOpt (ServerSocket, Sol_socket,
SO_REUSEADDR,
(const char *) &on, sizeof (on));

if ( -1 = status)
{
Perror ("setsockopt (..., so_reuseaddr,...)");
}

/* When the connection is interrupted, delay shutdown (linger) is required to ensure that all data
* be transmitted, so need to open so_linger this option
* The structure of the linger is defined in/usr/include/linux/socket.h:
* struct LINGER
*  {
* int L_onoff; /* Linger Active *
* int L_linger; /* How long to linger * *
*  };


* If the L_onoff is 0, the delay shutdown feature is canceled. If Non-zero, the socket interface is allowed to delay shutdown.
* The L_linger field indicates when the delay is closed
*/


{
struct Linger linger = {0};

Linger.l_onoff = 1;
Linger.l_linger = 30;
Status = SetSockOpt (ServerSocket,
Sol_socket, So_linger,
(const char *) &linger,
sizeof (linger));

if ( -1 = status)
{
Perror ("setsockopt (..., so_linger,...)");
}
}

/*
* Find out who I am
*/

Status = GetHostName (hostname,
sizeof (hostname));
if ( -1 = status)
{
Perror ("GetHostName ()");
Exit (1);
}

Hostptr = gethostbyname (hostname);
if (NULL = = hostptr)
{
Perror ("gethostbyname ()");
Exit (1);
}

(void) memset (&servername, 0,
  sizeof (serverName);
   (void) memcpy (&servername.sin_addr,
  hostptr->h_addr,
  hostptr->h_length);
/*
  *h_addr is a synonym for h_addr_list[0],
  * h_addr_list is an array of address sets
  * length 4 (byte) represents the length of an IP address
&nbs P */
/*
 * in order for the server to bind all IP addresses of the machine,
 * the preceding line of code requires the following code instead of
 * servername.sin_addr.s_addr=htonl ( Inaddr_any);
 */

Servername.sin_family = af_inet;
/* HTONS:H (host Byteorder)
* to N (network byteorder, network byte sequence
* s (short type)
*/
Ser Vername.sin_port = htons (port);
/* After an address (ServerSocket in this example) is established
 * it should be bound to the socket we obtained.
 */
Status = Bind (ServerSocket,
  (struct sockaddr *) &servername,
sizeof (serverName)); if ( -1 = = status)
{
Perror ("bind ()");
Exit (1);
}
/* Now the socket interface can be used to listen for new connections. The
 * back_log specifies the maximum length of the pending Connection listener queue (listen queue for pending connections)
 *. When a new connection arrives and the queue is full, the customer gets a connection rejection error.


* (This is the basis for DOS denial of service attacks).
*/
Status = Listen (ServerSocket, back_log);
if ( -1 = status)
{
Perror ("Listen ()");
Exit (1);
}
/* Starting from here, the socket is ready to accept requests and serve them.
* This example uses a for loop for this purpose. Once the connection is received (accpepted),
* The server can get the customer's address through pointers for some such things as logging customer login
Task
for (;;)
{
struct Sockaddr_in ClientName = {0};
int Slavesocket, clientlength =
sizeof (CLIENTNAME);


(void) memset (&clientname, 0,
sizeof (ClientName));

Slavesocket = Accept (ServerSocket,
(struct sockaddr *) &clientname,
&clientlength);
if ( -1 = slavesocket)
{
Perror ("Accept ()");
Exit (1);
}

Childpid = fork ();

Switch (CHILDPID)
{
Case-1:/* ERROR * *
Perror ("fork ()");
Exit (1);

Case 0: * * Child process * *

Close (ServerSocket);

if ( -1 = Getpeername (Slavesocket,
(struct sockaddr *) &clientname,
&clientlength))
{
Perror ("Getpeername ()");
}
Else
{
printf ("Connection request from%s\n",
Inet_ntoa (CLIENTNAME.SIN_ADDR));
}

/*
* Server Application specific code
* goes here, e.g. perform some
* Action, respond to client etc.
*/
Write (slavesocket, message,
strlen (message));
/* You can also use the ANSI function Fprint with caching,
* Refresh cache with Fflush as long as you remember if necessary
*/
Close (Slavesocket);
Exit (0);

Default:/* Parent Process * *
Close (slavesocket);/* It's a very good habit.
* The parent process closes the child process's set interface descriptor
* Just as the child process above closes the parent process's set interface descriptor.
*/
}
}

return 0;
}


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.