ch59.htm

来自「linux-unix130.linux.and.unix.ebooks130 l」· HTM 代码 · 共 1,177 行 · 第 1/2 页

HTM
1,177
字号


<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<SCRIPT>
<!--
function displayWindow(url, width, height) {
        var Win = window.open(url,"displayWindow",'width=' + width +
',height=' + height + ',resizable=1,scrollbars=yes');
}
//-->
</SCRIPT>
</HEAD>

 -->








<font face="Arial,Helvetica" size="-1" color="#006666">

<b>Linux</b></font><p>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">











 

























<UL>



	<LI><A HREF="#Heading1">- 59 -</A>



	<UL>



		<LI><A HREF="#Heading2">Network Programming</A>



		<UL>



			<LI><A HREF="#Heading3">Ports and Sockets</A>



			<LI><A HREF="#Heading4">Socket Programming</A>



			<UL>



				<LI><A HREF="#Heading5">The socket() System Call</A>



				<LI><A HREF="#Heading6">The bind() System Call</A>



				<LI><A HREF="#Heading7">The listen() System Call</A>



				<LI><A HREF="#Heading8">The accept() System Call</A>



				<LI><A HREF="#Heading9">The setsockopt() and getsockopt() System Calls</A>



				<LI><A HREF="#Heading10">The connect() System Call</A>



			</UL>



			<LI><A HREF="#Heading11">Listing 59.1. The server side for a socket-oriented protocol.</A>



			<LI><A HREF="#Heading12">Listing 59.2. The client side function.</A>



			<UL>



				<LI><A HREF="#Heading13">Connectionless Socket Programming</A>



			</UL>



			<LI><A HREF="#Heading14">Listing 59.3. The server side.</A>



			<LI><A HREF="#Heading15">NOTE</A>



			<LI><A HREF="#Heading16">Record and File Locking</A>



			<LI><A HREF="#Heading17">Interprocess Communications</A>



			<LI><A HREF="#Heading18">Summary</A>



		</UL>



	</UL>



</UL>







<P>



<HR SIZE="4">







<H2 ALIGN="CENTER"><A NAME="Heading1<FONT COLOR="#000077">- 59 -</FONT></H2>



<H2 ALIGN="CENTER"><A NAME="Heading2<FONT COLOR="#000077">Network Programming</FONT></H2>



<P><I>by Kamran Husain and Tim Parker</I></P>



<P>IN THIS CHAPTER</P>







<UL>



	<LI>Ports and Sockets 



	<P>



	<LI>Socket Programming 



	<P>



	<LI>Record and File Locking 



	<P>



	<LI>Interprocess Communications  



</UL>







<P><BR>



This chapter looks at the basic concepts you need for network programming:







<UL>



	<LI>Ports and sockets



	<P>



	<LI>Record and file locking



	<P>



	<LI>Interprocess communications



</UL>







<P>It is impossible to tell you how to program applications for a network in just



a few pages. Indeed, the best available reference to network programming takes almost



800 pages in the first volume alone! If you really want to do network programming,



you need a lot of experience with compilers, TCP/IP, and network operating systems--and



you need a great deal of patience.</P>



<P>For details on TCP/IP, check the book Teach Yourself TCP/IP in 14 Days, by Tim



Parker (Sams Publishing).



<H3 ALIGN="CENTER"><A NAME="Heading3<FONT COLOR="#000077">Ports and Sockets</FONT></H3>



<P>Network programming relies on the use of sockets to accept and transmit information.



Although there is a lot of mystique about sockets, the concept is actually simple



to understand.</P>



<P>Most applications that use the two primary network protocols, Transmission Control



Protocol (TCP) and User Datagram Protocol (UDP) have a port number that identifies



the application. A port number is used for each different application the machine



is handling, so it can keep track of those applications by numbers rather than names.



The port number makes it easier for the operating system to know how many applications



are using the system and which services are available.</P>



<P>In theory, port numbers can be assigned on individual machines by the system administrator,



but some conventions have been adopted to allow better communications. These conventions



enable the port number to identify the type of service that one system is requesting



from another. For this reason, most systems maintain a file of port numbers and their



corresponding services.</P>



<P>Port numbers are assigned starting from the number 1. Normally, port numbers above



255 are reserved for the private use of the local machine, but numbers between 1



and 255 are used for processes requested by remote applications or for networking



services.</P>



<P>Each network communications circuit into and out of the host computer's TCP application



layer is uniquely identified by a combination of two numbers, together called the



socket. The socket is composed of the IP address of the machine and the port number



used by the TCP software.</P>



<P>Because at least two machines are involved in network communications, there will



be a socket on both the sending and the receiving machine. Because the IP address



of each machine is unique and the port numbers are unique to each machine, socket



numbers are also unique across the network. This setup enables an application to



talk to another application across the network based entirely on the socket number.</P>



<P>The sending and receiving machines maintain a port table that lists all active



port numbers. The two machines involved have reversed entries for each session between



the two, a process called binding. In other words, if one machine has the source



port number 23 and the destination port number set at 25, the other machine has its



source port number set at 25 and the destination port number set at 23.



<H3 ALIGN="CENTER"><A NAME="Heading4<FONT COLOR="#000077">Socket Programming</FONT></H3>



<P>Linux supports BSD-style socket programming. Both connection-oriented and connectionless



types of sockets are supported. In connection-oriented communication, the server



and client establish a connection before any data is exchanged. In connectionless



communication, data is exchanged as part of a message. In either case, the server



always starts first, binds itself to a socket, and listens to messages. How the server



attempts to listen depends on the type of connection for which you have programmed



it.</P>



<P>You need to know about a few system calls:







<UL>



	<LI><TT>socket()</TT>



	<P>



	<LI><TT>bind()</TT>



	<P>



	<LI><TT>listen()</TT>



	<P>



	<LI><TT>accept()</TT>



	<P>



	<LI> setsockopt() and getsockopt()



	<P>



	<LI><TT>connect()</TT>



	<P>



	<LI><TT>sendto()</TT>



	<P>



	<LI><BR>



	recvfrom()



</UL>







<P>We will cover these system calls in the following examples.



<H4 ALIGN="CENTER"><A NAME="Heading5<FONT COLOR="#000077">The socket() System



Call</FONT></H4>



<P>The <TT>socket()</TT> system call creates a socket for the client or the server.



The <TT>socket</TT> function is defined as shown here:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;



int socket(int family, int type, int protocol)



</FONT></PRE>



<P>For Linux, you will have family<TT> = AF_UNIX</TT>. The type is either <TT>SOCK_STREAM</TT>



for reliable, though slower, communications or <TT>SOCK_DGRAM</TT> for faster, but



less reliable, communications. The protocol should be <TT>IPPROTO_TCP</TT> for <TT>SOCK_STREAM</TT>



and <TT>IPPROTO_UDP</TT> for <TT>SOCK_DGRAM</TT>.</P>



<P>The return value from this function is <TT>-1</TT> if there was an error; otherwise,



it's a socket descriptor. You will use this socket descriptor to refer to this socket



in all subsequent calls in your program.</P>



<P>Sockets are created without a name. Clients use the name of the socket to read



or write to it. This is where the <TT>bind</TT> function comes in.



<H4 ALIGN="CENTER"><A NAME="Heading6<FONT COLOR="#000077">The bind() System



Call</FONT></H4>



<P>The <TT>bind()</TT> system call assigns a name to an unnamed socket. The <TT>bind</TT>



function is defined like this:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;







int bind(int sockfd, struct sockaddr *saddr, int addrlen)



</FONT></PRE>



<P>The first item is a socket descriptor. The second is a structure with the name



to use, and the third item is the size of the structure.</P>



<P>Now that you have bound an address for your server or client, you can <TT>connect()</TT>



to it or listen on it. If your program is a server, it sets itself up to listen and



accept connections. Let's look at the function available for such an endeavor.



<H4 ALIGN="CENTER"><A NAME="Heading7<FONT COLOR="#000077">The listen() System



Call</FONT></H4>



<P>The <TT>listen()</TT> system call is used by the server. It is defined in the



following way:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;







int listen(int sockfd, int backlog);



</FONT></PRE>



<P>The sockfd is the descriptor of the socket. The backlog is the number of connections



that are pending at one time before any are rejected. Use the standard value of <TT>5</TT>



for backlog. A returned value of less than <TT>1</TT> indicates an error.</P>



<P>If this call is successful, you can accept connections.



<H4 ALIGN="CENTER"><A NAME="Heading8<FONT COLOR="#000077">The accept() System



Call</FONT></H4>



<P>The <TT>accept()</TT> system call is used by a server to accept any incoming messages



from clients' <TT>connect()</TT> calls. Be aware that this function does not return



if no connections are received. It is defined like this:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;







int accept(int sockfd, struct sockaddr *peeraddr, int addrlen)



</FONT></PRE>



<P>The parameters are the same as those for the <TT>bind</TT> call, with the exception



that the peeraddr points to information about the client that is making a connection



request. Based on the incoming message, the fields in the structure pointed at by



peeraddr are filled out.



<H4 ALIGN="CENTER"><A NAME="Heading9<FONT COLOR="#000077">The setsockopt()



and getsockopt() System Calls</FONT></H4>



<P>The socket libraries provided with Linux include a bug. The symptom of this bug



is that you cannot reuse a port number for a socket even if you closed the socket



properly. For example, say you write your own server that waits on a socket. This



server opens the socket and listens on it with no problems. However, for some reason



(a crash or normal termination), when the program is restarted, you are not able



to bind to the same port. The error codes from the <TT>bind()</TT> call will always



return an error indicating that the port you are attempting to connect to is already



bound to another process.</P>



<P>The problem is that the Linux kernel never marks the port as unused when the process



bound to a socket terminates. In most other UNIX systems, the port can be used again



by another invocation of the same or even another process.</P>



<P>The way to get around this problem in Linux is to use the <TT>setsockopt()</TT>



system call to set the options on a socket when it is opened and before a connection



is made on it. The <TT>setsockopt()</TT> sets options and the <TT>getsockopt()</TT>call



gets options for a given socket.</P>



<P>Here is the syntax for these calls:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;







int getsockopt(int sockfd, int level, int name, char *value, int *optlen)



</FONT></PRE>







<PRE><FONT COLOR="#0066FF">int setsockopt(int sockfd, int level, int name, char *value, int *optlen)



</FONT></PRE>



<P>The sockfd must be an open socket. The level is the protocol level to use for



the function (<TT>IPPROTO_TCP</TT> for TCP/IP and <TT>SOL_SOCKET</TT> for socket



level options), and the name of the option is as defined in the socket's man page.



The *value pointer points to a location where a value is stored for <TT>getsockopt()</TT>



or when a value is read for <TT>setsockopt()</TT>. The optlen parameter is a pointer



to an integer containing the length of the parameters in bytes; the value is set



by <TT>getsockopt()</TT> and must be set by the programmer when making a call via



<TT>setsockopt()</TT>.</P>



<P>The full man page with details of all the options is found in the man page <TT>setsockopt(2)</TT>.</P>



<P>Now back to the bug in Linux. When you open a socket, you must also call the <TT>setsockopt()</TT>



function with the following segment of code:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#ifdef LINUX



opt = 1; len = sizeof(opt);



setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&amp;opt,&amp;len);







#endif



</FONT></PRE>



<P>The <TT>#ifdef</TT> and <TT>#endif</TT> statements are necessary only if you want



to port the code over to systems other than Linux. Some UNIX systems might not support



or require the <TT>SO_REUSEADDR</TT> flag.



<H4 ALIGN="CENTER"><A NAME="Heading10<FONT COLOR="#000077">The connect() System



Call</FONT></H4>



<P>The <TT>connect()</TT> system call is used by clients to connect to a server in



a connection-oriented system. This <TT>connect()</TT> call should be made after the



<TT>bind()</TT> call. It is defined like this:<FONT COLOR="#0066FF"></FONT>



<PRE><FONT COLOR="#0066FF">#include&lt;sys/types.h&gt;



#include&lt;sys/socket.h&gt;







int connect(int sockfd, struct sockaddr *servsaddr, int addrlen)



</FONT></PRE>



<P>The parameters are the same as those for the <TT>bind</TT> call, with the exception



that the servsaddr points to information about the server that the client is connecting



to. The <TT>accept</TT> call creates a new socket for the server to work with the



request. This way, the server can <TT>fork()</TT> off a new process and wait for



more connections. On the server side of things, you would have code that looks like



that shown in Listing 59.1.



<H3 ALIGN="CENTER"><A NAME="Heading11<FONT COLOR="#000077">Listing 59.1. The



server side for a socket-oriented protocol.</FONT><FONT COLOR="#0066FF"></FONT></H3>



<PRE><FONT COLOR="#0066FF">#include    &lt;sys/types.h&gt;



#include    &lt;sys/socket.h&gt;



#include &lt;linux/in.h&gt;



#include &lt;linux/net.h&gt;







#define MY_PORT 6545







main(int argc, char *argv[])



{



int sockfd, newfd;



int cpid; /* child id */



struct sockaddr_in servaddr;



struct sockaddr_in clientInfo;







if ((sockfd = socket(AF_INET, SOCK_STREAM, 0) &lt; 0)



    {



    myabort(&quot;Unable to create socket&quot;);



    }







#ifdef LINUX



opt = 1; len = sizeof(opt);



setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&amp;opt,&amp;len);



#endif







bzero((char *)&amp;servaddr, sizeof(servaddr));





⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?