Linux network programming, Part 1: BSD interface (Part 2)

Source: Internet
Author: User
Tags htons

(Part 1)
2. Create the corresponding client
As you can see, the client code is much simpler than the server. In this program, you must provide two command line parameters: the host name or IP address of the server, and the port bound to the service segment. Of course, the server must also run normally before the client runs: P.

/*
* Listing 2:
* An example client for "hello, world! "Server
* Ivan Griffin in (ivan.griffin@ul.ie)
*/

/* Hellwolf misty translated */

# Include <stdio. h>/* perror ()*/
# Include <stdlib. h>/* atoi ()*/
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <unistd. h>/* read ()*/
# Include <netinet/in. h>
# Include <ARPA/inet. h>
# Include <netdb. h>

Int main (INT argc, char * argv [])
{
Int clientsocket,
Remoteport,
Status = 0;
Struct hostent * hostptr = NULL;
Struct sockaddr_in servername = {0 };
Char buffer [256] = "";
Char * remotehost = NULL;

If (3! = Argc)
{
Fprintf (stderr, "Usage: % s
/N ",
Argv [0]);
Exit (1 );
}

Remotehost = argv [1];
Remoteport = atoi (argv [2]);

Clientsocket = socket (pf_inet, sock_stream,
Ipproto_tcp );
If (-1 = clientsocket)
{
Perror ("socket ()");
Exit (1 );
}

/*
* The first assumption is the DNS host name.
* Note:
* Struct hostent {
* Char * h_name;/* official name of Host */
* Char ** h_aliases;/* alias list */
* Int h_addrtype;/* Host address type */
* Int h_length;/* length of address */
* Char ** h_addr_list;/* list of addresses from name server */
*};
* # Define h_addr h_addr_list [0]
* Have you noticed this? H_addr is a macro.
* Display phostent-> h_addr. Do not be surprised when an error occurs.
*/
Hostptr = gethostbyname (remotehost);/* struct hostent * hostptr ;*/
If (null = hostptr)
{/* No ?? */
Hostptr = gethostbyaddr (remotehost,
Strlen (remotehost), af_inet);/* it should be an IP address in the form of points */
If (null = hostptr)/* is not ,! -_-*/
{
Perror ("error resolving server address ");
Exit (1 );
}
}

Servername. sin_family = af_inet;
Servername. sin_port = htons (remoteport );
(Void) memcpy (& servername. sin_addr,
Hostptr-> h_addr,
Hostptr-> h_length );

/* BIND is not required here, because CONNECT can solve everything for us */
Status = connect (clientsocket,
(Struct sockaddr *) & servername,
Sizeof (servername ));
If (-1 = Status)
{
Perror ("Connect ()");
Exit (1 );
}
/* After successful connect, a duplex network connection is established.
* Like a server, a client can use read () and write () to receive data.
/*
* The specific client code should be implemented from here
* For example, receiving and responding to messages from the server
*/
While (0 <(status = read (clientsocket,
Buffer, sizeof (buffer)-1 )))
{
Printf ("% d: % s", status, buffer );
/* Note: If the read succeeds, status indicates the number of bytes (including '/0 ')*/
}

If (-1 = Status)
{
Perror ("Read ()");
}

Close (clientsocket );

Return 0;
}

Notes:

  • Text sending usually works normally. But remember that different systems have different implementations for line breaks (for example, Unix uses/0x12 while Microsoft uses/0x15/0x12 ).
  • Different implementations may use different byte-order ). But don't worry. BSD designers have considered this. There are many ready-made functions that implement this type of conversion. They all have certain naming rules: htons represents the transformation of the short structure of the host-to-network, as well as htonl, ntohs, ntohl, it is also easy to determine how they work. Whether the network's byte sequence is big-Endian or little-Endian is not a problem because it has been standardized on TCP/IP networks (note: the network uses the large-end alignment in the byte order ). Of course, unless you have been posting a character on the Network (Note: It must be ASCII), these conversion functions won't cause a big problem, but usually you will encounter a byte order problem. This depends on your machine. Sometimes these functions are empty macros, and sometimes they are indeed functions. Interestingly, the most common source of network programming bugs is that you forgot to use these functions when filling the sin_addr.s_addr field in the sockaddr_in structure, even if you use inaddr_any.
  • An important goal of network programming is not to bring unexpected troubles to both parties. For example, when the server accesses key data, it must use the necessary mechanisms to synchronize access to this part of the resource, avoiding the resulting deadlock and ensuring the effectiveness of the data.
  • In most cases, you cannot pass a pointer between machines and try to use it.
    <> Similarly, in most cases, you cannot try to pass a file descriptor from one process to another (non-child process) through a set of interfaces and use it directly. The BSD and svr4 systems provide different methods for transferring file descriptors between unrelated processes. However, in Linux, the easiest way is to use the/proc file system.
  • In addition, you must ensure that you have properly solved the short writes problem. The short write occurs when the write () call only partially writes the buffer to the device corresponding to a file descriptor. They are caused by the operating system buffer zone and the flow control system of the underlying transmission system. Some system calls, usually called slow system calls (slow system CILS), may be interrupted by (other calls. Some may not be automatically restarted, so you must solve this problem explicitly during network programming. The following code solves the short write problem:
    /*
    * Listing 3:
    * Handling short writes
    * Ivan Griffin in (ivan.griffin@ul.ie)
    */
    /* Hellwolf misty translated */
    Int bytestosend = 0,
    Byteswritten = 0,
    Num = 0;

/*
* Bytestosend, buffer, and used here
* Filedesc must have been defined somewhere else.
*/

For (byteswritten = 0; byteswritten <bytestosend;
Byteswritten + = num)
{
Num = write (filedesc,
(Void *) (char *) buffer +
(Char *) byteswritten ),
Bytestosend-byteswritten );

If (Num <0)
{
Perror ("write ()");

If (errno! = Eintr)
{
Exit (1 );
}
}
}

Using multithreading instead of multiple processes may reduce the burden on the server and be more effective. Context conversion between threads (of course, the same process space) usually has much lower overhead than context conversion between processes. However, so many sub-threads are operating on network I/O, if they are still available at the kernel level, but if they are user-level, the whole process will be blocked by the first thread that calls I/O. This will cause other threads that are unwilling to be seen to become hungry until I/O is completed. As you can see, when using a simple forking model, it is quite common to disable unnecessary set of interface file descriptors in the parent process and child process. This protects the process from the possibility of reading and writing these descriptors with potential errors. But do not try to do this when using the thread model. multithreading in the process shares the same memory virtual address space and file descriptor set. If you disable a descriptor in a thread, all other threads in the process cannot obtain the descriptor.

3. connectionless data transmission-udp
The following code shows a server that uses UDP. UDP programs are similar to TCP programs, but they are quite different. First, UDP does not guarantee reliable transmission-if you need to obtain reliability when using UDP, you must implement or use TCP instead.

Like a TCP program, you can use UDP to create a set of interfaces and bind them to a specific address. The UDP server does not listen to (Listen) or accept (accept) external connections, and the customer does not need to explicitly connect to the server. In fact, there is no big difference between the UDP client and the service segment. The server must be bound to a specific port and address to let the client know where to send data. And when your server uses send (), the client should also use the corresponding Recv family function.
UDP server program list:
/*
* Listing 4:
* Example UDP (connectionless) Server
* Ivan Griffin in (ivan.griffin@ul.ie)
*/

# Include <stdio. h>
# Include <stdlib. h>
# Include <string. h>
# Include <sys/uio. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <netinet/in. h>
# Include <ARPA/inet. h>
# Include <netdb. h>

# Define max_mesg_size 4096
Char mesg [max_mesg_size] = "";

Int main (INT argc, char * argv [])
{
Int udpsocket = 0,
Myport = 0,
Status = 0,
Size = 0,
Clientlength = 0;
Struct sockaddr_in servername = {0 },
Clientname = {0 };

If (2! = Argc)
{
Fprintf (stderr, "Usage: % s /N ",
Argv [0]);
Exit (1 );
}

Myport = atoi (argv [1]);

Udpsocket = socket (pf_inet, sock_dgram,/* the combination of pf_inet and sock_dgram represents udp */
Ipproto_udp );
If (-1 = udpsocket)
{
Perror ("socket ()");
Exit (1 );
}

Memset (& servername, 0, sizeof (servername ));
Memset (& clientname, 0, sizeof (clientname ));

Servername. sin_family = af_inet;
Servername. sin_addr.s_addr = htonl (inaddr_any );
Servername. sin_port = htons (myport );

Status = BIND (udpsocket, (struct sockaddr *)
& Servername, sizeof (servername ));
If (-1 = Status)
{
Perror ("BIND ()");
Exit (1 );
}

For (;;)
{
/* Ssize_t recvfrom (int s, void * Buf, size_t Len, int flags, struct sock-
* ADDR * From, socklen_t * fromlen );
*/
Size = recvfrom (udpsocket, mesg,
Max_mesg_size, 0,
(Struct sockaddr *) & clientname,
& Clientlength );
If (size =-1)
{
Perror ("recvfrom ()");
Exit (1 );
}
/* Ssize_t sendto (int s, const void * MSG, size_t Len, int flags, const
* Struct sockaddr * To, socklen_t tolen );
*/
Status = sendto (udpsocket, mesg, size, 0,
(Struct sockaddr *) & clientname,
Clientlength );
If (status! = Size)
{
Fprintf (stderr,
"Sendto (): short write./N ");
Exit (1 );
}
}

/* Never reached */
Return 0;
}

Rewrite the tcp client to the UDP client for another exercise.

4./etc/services file
To connect to a server, you must first know the listening address and port. The information of many common services (such as FTP and telnet) is listed in a text file.

In/etc/services. The getservbyname () function can use a name to query the details of a service, including its port number (note! It is already in the network byte order), and its prototype is in

/Usr/include:
Struct servent * getservbyname (const char * Name, const char * PROTO); default Proto is "TCP"

Struct servent
{
Char * s_name;/* Official service name */
Char ** s_aliases;/* alias list */
Int s_port;/* port number, Network
* Byte-order -- so do not
* Use host-to-network macros */
Char * s_proto;/* protocol to use */
};

5. Summary
This article describes how to use C and BSD socket APIs for network programming in Linux. In general, using this set of APIs to write code will be quite labor-consuming, especially with other

Compared with other technologies. In future articles, I will compare the BSD Socket API with the other two methods in Linux: Remote Procedure Call (rpcs, Remote Procedure

Common Object Request Broker Achitecture, Common Object Request proxy [scheduling] program architecture ). Rpcs in Ed PETRON's article "remote

Procedure CILS "(Linux journal issue # October) is described in.

Related Resources:
UNIX network programming, W. Richard Steve, Prentice Hall, 1990.

An introductory 4.4bsd Interprocess Communication tutorial, Stuart sechrest, University of California, Berkeley. 1986.

Available via anonymous FTP at: ftp://ftp.NetBSD.ORG/pub/NetBSD/misc/lite2-docs/psd/20.ipctut.ps.gz.

An advanced 4.4bsd Interprocess Communication tutorial, Samuel J. Leffler, Robert S. Fabry, William N. Joy, Phil Lapsley,

University of California, Berkeley. 1986 available via anonymous FTP at: ftp://ftp.NetBSD.ORG/pub/NetBSD/misc/lite2-

Docs/PSD/21.ipc.ps.gz.

Java and the client-server, Joe novosel, Linux Journal, Issue 33, January 1997.

RFC 793: Transmission Control Protocol, J. Postel (ed.), September 1981. available via HTTP

Http://www.internic.net/rfc/rfc793.txt.

RFC 1337: Time-Wait assassination hazards in TCP, R. Braden, May 1992. available via HTTP

Http://www.internic.net/rfc/rfc1337.txt.

Programming UNIX sockets in c faq, Vic Metcalfe, Andrew gierth and other contributers, February 1997. available via HTTP

Http://kipper.york.ac.uk /~ Vic/sock-faq/html/unix-socket-faq.html

Author profile:
Ivan Griffin in is a research postgraduate student in the ECE department at the University of Limerick, Ireland. His interests

Include C ++/Java, WWW, ATM, the UL Computer Society (http://www.csn.ul.ie/) and, of course, Linux

Http://www.trc.ul.ie /~ Griffin/linux.html). His e-mail address is ivan.griffin@ul.ie.

Dr. John Nelson is a senior lecturer in computer engineering at the University of Limerick. His interests include mobile

Communications, intelligent networks, software engineering and large-scale design. His e-mail address is john.nelson@ul.ie.

All programs can be obtained here: ftp://ftp.ssc.com/pub/lj/listings/issue46/2333.tgz

Related Article

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.