ch59.htm
来自「linux-unix130.linux.and.unix.ebooks130 l」· HTM 代码 · 共 1,177 行 · 第 1/2 页
HTM
1,177 行
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_family = htons(MY_PORT);
/*
* The htonl (for a long integer) and htons (for short integer) convert
* a host oriented byte order * into a network order.
*/
if (bind(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr)) < 0)
{
myabort("Unable to bind socket");
}
listen(sockfd,5);
for (;;)
{
/* wait here */
newfd=accept(sockfd,(struct sockaddr *)&clientInfo,
sizeof(struct sockaddr);
if (newfd < 0)
{
myabort("Unable to accept on socket");
}
if ((cpid = fork()) < 0)
{
myabort("Unable to fork on accept");
}
else if (cpid == 0) { /* child */
close(sockfd); /* no need for original */
do_your_thing(newfd);
exit(0);
}
close(newfd); /* in the parent */
}
</FONT></PRE>
<PRE><FONT COLOR="#0066FF">}
</FONT></PRE>
<P>In the case of connection-oriented protocols, the server performs the following
functions:
<UL>
<LI>Creates a socket with a call to the <TT>socket()</TT> function
<P>
<LI>Binds itself to an address with the <TT>bind()</TT> function call
<P>
<LI>Listens for connections with the <TT>listen()</TT> function call
<P>
<LI>Accepts any incoming requests with the <TT>accept()</TT> function call
<P>
<LI>Gets incoming messages with the <TT>read()</TT> function and replies with the
<TT>write()</TT> call
</UL>
<P>Now let's look at the client side of things, in Listing 59.2.
<H3 ALIGN="CENTER"><A NAME="Heading12<FONT COLOR="#000077">Listing 59.2. The
client side function.</FONT><FONT COLOR="#0066FF"></FONT></H3>
<PRE><FONT COLOR="#0066FF">#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/net.h>
#define MY_PORT 6545
#define MY_HOST_ADDR "204.25.13.1"
int getServerSocketId()
{
int fd, len;
struct sockaddr_in unix_addr;
/* create a Unix domain stream socket */
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
return(-1);
}
#ifdef LINUX
opt = 1; len = sizeof(opt);
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,&len);
#endif
/* fill socket address structure w/our address */
memset(&unix_addr, 0, sizeof(unix_addr));
unix_addr.sin_family = AF_INET;
/* convert internet address to binary value*/
unix_addr.sin_addr.s_addr = inet_addr(MY_HOST_ADDR);
unix_addr.sin_family = htons(MY_PORT);
if (bind(fd, (struct sockaddr *) &unix_addr, len) < 0)
return(-2);
memset(&unix_addr, 0, sizeof(unix_addr));
if (connect(fd, (struct sockaddr *) &unix_addr, len) < 0)
return(-3);
return(fd);
}
</FONT></PRE>
<P>The client for connection-oriented communication also takes the following steps:
<UL>
<LI>Creates a socket with a call to the <TT>socket()</TT> function
<P>
<LI>Attempts to connect to the server with a <TT>connect()</TT> call
<P>
<LI>If a connection is made, requests data with the <TT>write()</TT> call, and reads
incoming replies with the <TT>read()</TT> function
</UL>
<H4 ALIGN="CENTER"><A NAME="Heading13<FONT COLOR="#000077">Connectionless Socket
Programming</FONT></H4>
<P>Now let's consider the case of a connectionless exchange of information. The principle
on the server side is different from the connection-oriented server side in that
the server calls <TT>recvfrom()</TT> rather than the <TT>listen</TT> and <TT>accept</TT>
calls. Also, to reply to messages, the server uses the <TT>sendto()</TT> function
call. See Listing 59.3 for the server side.
<H3 ALIGN="CENTER"><A NAME="Heading14<FONT COLOR="#000077">Listing 59.3. The
server side.</FONT><FONT COLOR="#0066FF"></FONT></H3>
<PRE><FONT COLOR="#0066FF">#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/net.h>
#define MY_PORT 6545
#define MAXM 4096
char mesg[MAXM];
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) < 0)
{
myabort("Unable to create socket");
}
#ifdef LINUX
opt = 1; len = sizeof(opt);
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,&len);
#endif
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_family = htons(MY_PORT);
/*
* The htonl (for a long integer) and htons (for short integer) convert
* a host oriented byte order * into a network order.
*/
if (bind(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr)) < 0)
{
myabort("Unable to bind socket");
}
for (;;)
{
/* wait here */
n = recvfrom(sockfd, mesg, MAXM, 0,
(struct sockaddr *)&clientInfo,
sizeof(struct sockaddr));
doSomethingToIt(mesg);
sendto(sockfd,mesg,n,0,
(struct sockaddr *)&clientInfo,
sizeof(struct sockaddr));
}
}
</FONT></PRE>
<P>As you can see, the two function calls to process each message make this an easier
implementation than a connection-oriented one. You must, however, process each message
one at a time because messages from multiple clients can be multiplexed together.
In a connection-oriented scheme, the child process always knows where each message
originated.</P>
<P>The client does not have to call the <TT>connect()</TT> system call either. Instead,
the client can call the <TT>sendto()</TT> function directly. The client side is identical
to the server side, with the exception that the <TT>sendto</TT> call is made before
the <TT>recvfrom()</TT>call:</P>
<PRE><FONT COLOR="#0066FF">#include <sys/types.h>
#include <sys/socket.h>
int sendto((int sockfd,
const void *message__, /* the pointer to message */
int length, /* of message */
unsigned int type, /* of routing, leave 0 */
const struct sockaddr * client, /* where to send it */
int length ); /* of sockaddr */
</FONT></PRE>
<DL>
<DT><FONT COLOR="#0066FF"></FONT></DT>
</DL>
<DL>
<DD>
<HR>
<A NAME="Heading15<FONT COLOR="#000077"><B>NOTE: </B></FONT>If you are a BSD
user, use the <TT>sendto()</TT> call, not the <TT>sendmsg()</TT> call. The <TT>sendto()</TT>
call is more efficient.
<HR>
</DL>
<P>Any errors are indicated by a return value of <TT>-1</TT>. Only local errors are
detected.</P>
<P>The <TT>recvfrom()</TT> system call is defined as shown here:<FONT COLOR="#0066FF"></FONT>
<PRE><FONT COLOR="#0066FF">#include <sys/types.h>
#include <sys/socket.h>
int recvfrom(int sockfd,
const void *message__, /* the pointer to message */
int length, /* of message */
unsigned int flags, /* of routing, leave 0 */
const struct sockaddr * client, /* where to send it */
int length ); /* of sockaddr */
</FONT></PRE>
<P>If a message is too long to fit in the supplied buffer, the extra bytes are discarded.
The call might return immediately or wait forever, depending on the type of the flag
being set. You can even set timeout values. Check the man pages for <TT>recvfrom</TT>
for more information.</P>
<P>There you have it--the very basics of how to program applications to take advantage
of the networking capabilities under Linux. We have not even scratched the surface
of all the intricacies of programming for networks. A good starting point for more
detailed information would be UNIX Network Programming, by W. Richard Stevens (Prentice
Hall, 1990). This book, a classic, is used in most universities and is by far the
most detailed book to date.
<H3 ALIGN="CENTER"><A NAME="Heading16<FONT COLOR="#000077">Record and File
Locking</FONT></H3>
<P>When two processes want to share a file, the danger exists that one process might
affect the contents of the file, and thereby affect the other process. For this reason,
most operating systems use a mutually exclusive principle: when one process has a
file open, no other process can touch it. This is called file locking.</P>
<P>This technique is simple to implement. What usually happens is that a "lock
file" is created with the same name as the original file but with the extension
<TT>.lock</TT>, which tells other processes that the file is unavailable. This is
how many Linux spoolers, such as the print system and UUCP, implement file locking.
It is a brute-force method, perhaps, but effective and easy to program.</P>
<P>Unfortunately, this technique is not good when you must have several processes
access the same information quickly, because the delays waiting for file opening
and closing can grow to be appreciable. Also, if one process doesn't release the
file properly, other processes can hang there, waiting for access.</P>
<P>For this reason, record locking is sometimes implemented. With record locking,
a single part of a larger file is locked to prevent two processes from changing its
contents at the same time. Record locking enables many processes to access the same
file at the same time, each updating different records within the file, if necessary.
The programming necessary to implement record locking is more complex than that for
file locking, of course.</P>
<P>Normally, to implement record locking, you use a file offset, or the number of
characters from the beginning of the file. In most cases, a range of characters is
locked; the program has to note the start of the locking region and the length of
it, and then store that information where other processes can examine it.</P>
<P>Writing either file-locking or record-locking code requires a good understanding
of the operating system but is otherwise not difficult, especially because thousands
of programs are readily available from the Internet, in networking programming books,
and on BBSs to examine for sample code.
<H3 ALIGN="CENTER"><A NAME="Heading17<FONT COLOR="#000077">Interprocess Communications</FONT></H3>
<P>Network programming always involves two or more processes talking to each other
(interprocess communications), so the way in which processes communicate is vitally
important to network programmers. Network programming differs from the usual method
of programming in a few important aspects. A traditional program can talk to different
modules (or even other applications on the same machine) through global variables
and function calls. That doesn't work across networks.</P>
<P>A key goal of network programming is to ensure that processes don't interfere
with each other. Otherwise, systems can get bogged down or can lock up. Therefore,
processes must have a clean and efficient method of communicating. UNIX is particularly
strong in this regard, because many of the basic UNIX capabilities, such as pipes
and queues, are used effectively across networks.</P>
<P>Writing code for interprocess communications is quite difficult compared to single
application coding. If you want to write this type of routine, you should study sample
programs from a network programming book or a BBS site to see how this task is accomplished.
<H3 ALIGN="CENTER"><A NAME="Heading18<FONT COLOR="#000077">Summary</FONT></H3>
<P>Few people need to write network applications, so the details of the process are
best left to those who want them. Experience and lots of examples are the best way
to begin writing network code, and mastering the skills can take many years.
</td>
</tr>
</table>
<!-- begin footer information -->
</body></html>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?