Translation preface:
This article is selected from a series of articles in Linux Journal, Linux Network Programming, and has been partially modified. You may say a lot of articles on the internet programming, but this is my first translation. This is a new attempt to me. What kind of comments or suggestions are welcome to contact me: Hellwolf_ok @ sina. COM
Linux network programming, first part
BSD socket - This is the first article on how to use a variety of interfaces that can develop network programs for Linux development network programs. Just like most UNIX-based operating systems, Linux supports TCP / IP as a local network transport protocol. In this series, we assume that you have been familiar with C programming and some system knowledge of Linux, such as Signals, Forking, and more. This article is about how to create a network program with a BSD socket. In the next article, we will resolve issues involving the establishment (network) DEAMON process. And future articles we will also involve using the remote process call (RPC), and develop with CORBA / Distributed Objects.
I. TCP / IP Basic introduction TCP / IP protocol allows two procedures running on two computers running together by the same computer or by networking. This protocol is specifically designed in order to communicate on an unreliable network. TCP / IP allows two basic operating modes - Connected reliable transmission (referred to as TCP) and ConnectionLess) unreliable transmission (UDP). The following figure illustrates the hierarchical structure of the TCP / IP protocol.
The TCP provides a relay function, sequential, reliable, bidirectional, in connection-based byte transport stream with transparent relay functions such as the upper protocol. TCP splits your information into a datagram (no more than 64KB) and ensures that all datagrams are unmistable to reach the destination. Since a virtual connection must be established before a network entity (Network Entity) and the other. Contrary to UDP provides a (very fast) unconnected unreliable message transmission (the size of the message is a determined maximum length). In order to make the program can communicate with each other, whether they are in the same machine (via the loopback interface) or different hosts, each program must have a separate address. The TCP / IP address consists of two parts - the port address used to identify the IP address of the machine and the port address used to identify the specific programs on that machine. The address can be the form of dotted-quad symbols (eg, 127.0.0.1) or in the form of hostnamers (eg, www.9cbs.net). The system can use the / etc / hosts or DNS domain name service (if available), the host name to the point symbol address (that is, IP address). The port is numbered from the 1st. 1 and IPP0RT_RESERVED (defined in /usr/include/netinet/in.h, the segment slogan between usage between 1024) is reserved to the system (that is, you must build a network service as root to bind this Partial port). The simplest network program is mostly used by the customer - server model. A service process waits for a customer process to connect him. When the connection is established, the server performs a specific task on behalf of the customer, usually this will be interrupted later.
Second, the most popular TCP / IP programming method using the BSD socket interface is to use the BSD socket interface programming. Through it, network endpoints (IP address and port address) appear in the form of sockets. This set of interface IPC (Interprocess Communication, Process) The design of the facility (starting from 4.2BSD) is to allow the network program to design independently of different underlying communication facilities. 1. Create a server program To create a server program using the BSD interface, you must pass the following steps: 1. Set a socket 2 through the function socket (). A address (IP address and port address) is bound through the function bind (). This step determines the location of the server so that the client knows how to access. 3. Through the new connection request of the Listen port through the function list. 4. New connections are accepted by function accept (). Usually, maintenance represents a customer's request may take a long time. Receiving and processing new requests should also be efficient when processing a request. The most common approach to this purpose is to let the server copy a new connection through the fork () function. (The following figure: The representation of the client server code model) The following example shows how the server is implemented using C: / * * Simple "Hello, World!" Server * Ivan Griffin (Ivan.griff@ul.ie) * /
/ * Hellwolf MISTY TRANSLATED * /
#include
/ * * Constants * / const char message [] = "Hello, World! / N"; const INT back_log = 5;
/ * * Program requires a command line parameter: the port number required to be bound * / int main (int Argc, char * argv [] = 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 ", PF_INET (IPv4), * PF_INET6 (IPv6), etc. * 2, TYPE indicates the type of communication, the most commonly used SOCK_STREAM Reliable mode, * such as TCP), SOCK_DGRAM (non-connection non-reliable, such as UDP), and the like. * 3, parameter protocol Specifies the protocol you need to use. Although different protocol * parameters can be specified for the same protocol * family (or communication domain), only one is only one. For TCP parameters, IPPROTO_TCP can be specified, and IPPROTO_UDP can be used for * UDP. You don't have to explicitly develop this parameter, use 0, according to the previous * two parameters use the default protocol. * / Serversocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (-1 == Serversocket) {PERROR ("socket ()"); exit (1);} / * * Once set, it is established, its operation mechanism You can modify it through a socket option (Socket Option). * // * * SO_REUSEADDR option setting Set the socket to reuse the old address (IP address plus port number) without waiting: In the Linux system, if a socket is bound to a port, the socket is normal After the shutdown or program exits, * In a period of time, the port remains binded, other programs (or restarted the original program) cannot bind to the port. * * In the call: SOL_Socket represents the Socket layer to operate * / 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, it is necessary to delay the closure to ensure that all data is transmitted. {* Int L_ONOFF; / * linger activity * / * int L_linger; / * how long to linger * / *}; * If l_onoff is 0, the delay closure feature is canceled. If non-zero, the socket is allowed to close. * L_Linger field indicates the time * / {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 (& hostPtr- hostPtr- h_length serverName.sin_addr,> h_addr,>); / * * h_addr is h_addr_list [0] synonym, * h_addr_list is A set of addresses of an address * length is 4 (byte) representing the length of an IP address * // * * In order to bind the server all IP addresses, * The above line code needs to replace * Servername.sin_addr with the following code. s_addr = htonl (inaddr_any); * /
ServerName.sin_Family = AF_INET; / * HTONS: H (Host Byteorder, host word sequence) * to n (Network Byteorder, Network word * S (short type) * / servername.sin_port = htons (port); / * After an address (serversocket in this example) is created * it should be bound to our socket. * / Status = bind (STRUCT SOCKADDR *) & ServerName, SIZEOF (ServerName)); if ( -1 == status) {PERROR ("Bind ()"); exit (1);} / * Now sockets can be used to listen to new connections. * Back_log Specifies the unregrand connection monitor queue (Listen Queue for PENDING Connections * The maximum length. When a new connection arrives, the queue is full, the customer will get a connection to reject the error. * (This is the foundation of the DOS denial of service attack). * / status = listen (Serversocket, Back_log ); If (-1 == status) {PERROR ("Listen ()"); exit (1);} / * From here, the socket begins to prepare the request and serve them. * This example is used For loop to achieve this. Once the connection is accepted, the server can obtain the customer's address through the pointer to make some * tasks such as recording the customer login. for (;;) {struct sockaddr_in clientname = {0} Int slaveSocket, ClientLength = SizeOf (ClientName); (Void) Memset (& ClientName, 0, Sizeof (ClientName);
SlaveSocket = Accept (STRUCT SOCKADDR *) & ClientName, & ClientLength; if (-1 == slaveesocket) {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, Eg Perform Some * Action, respond to client etc. * / Write (slaveSocket, Message, Strlen (Message)); / * You can also use a cached ANSI function FPRINT, * As long as you remember, use FFLUSH to refresh the cache * / close (Slavesocket); exit (0);
Default: / * Parent Process * / Close (Slavesocket); / * This is a very good habit * The parent process shutdown sub-process socket descriptor * As the child process is close to the socket descriptor of the parent process. * /}}
Return 0;}