📄 24.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> ● UNIX网络编程 (BM: clown) </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="16.htm">上一层</a>][<a href="25.htm">下一篇</a>]
<hr><p align="left"><small>发信人: fion (fion), 信区: UNP <br>
标 题: unix socket faq (3) <br>
发信站: UNIX编程 (2001年07月07日09:42:56 星期六), 站内信件 <br>
<br>
2. Questions regarding both Clients and Servers (TCP/SOCK_STREAM) <br>
<br>
2.1. How can I tell when a socket is closed on the other end? <br>
From Andrew Gierth (andrew@erlenstar.demon.co.uk): <br>
AFAIK: <br>
If the peer calls close() or exits, without having messed with <br>
SO_LINGER, then our calls to read() should return 0. It is less clear <br>
what happens to write() calls in this case; I would expect EPIPE, not <br>
on the next call, but the one after. <br>
If the peer reboots, or sets l_onoff = 1, l_linger = 0 and then <br>
closes, then we should get ECONNRESET (eventually) from read(), or <br>
EPIPE from write(). <br>
I should also point out that when write() returns EPIPE, it also <br>
raises the SIGPIPE signal - you never see the EPIPE error unless you <br>
handle or ignore the signal. <br>
If the peer remains unreachable, we should get some other error. <br>
I don't think that write() can legitimately return 0. read() should <br>
return 0 on receipt of a FIN from the peer, and on all following <br>
calls. <br>
calls. <br>
So yes, you must expect read() to return 0. <br>
As an example, suppose you are receiving a file down a TCP link; you <br>
might handle the return from read() like this: <br>
rc = read(sock,buf,sizeof(buf)); <br>
if (rc > 0) <br>
{ <br>
write(file,buf,rc); <br>
/* error checking on file omitted */ <br>
} <br>
else if (rc == 0) <br>
{ <br>
close(file); <br>
close(sock); <br>
/* file received successfully */ <br>
} <br>
else /* rc < 0 */ <br>
{ <br>
/* close file and delete it, since data is not complete <br>
report error, or whatever */ <br>
} <br>
<br>
2.2. What's with the second parameter in bind()? <br>
The man page shows it as "struct sockaddr *my_addr". The sockaddr <br>
struct though is just a place holder for the structure it really <br>
wants. You have to pass different structures depending on what kind <br>
of socket you have. For an AF_INET socket, you need the sockaddr_in <br>
structure. It has three fields of interest: <br>
sin_family <br>
Set this to AF_INET. <br>
sin_port <br>
The network byte-ordered 16 bit port number <br>
sin_addr <br>
The host's ip number. This is a struct in_addr, which contains <br>
only one field, s_addr which is a u_long. <br>
<br>
2.3. How do I get the port number for a given service? <br>
Use the getservbyname() routine. This will return a pointer to a <br>
servent structure. You are interested in the s_port field, which <br>
contains the port number, with correct byte ordering (so you don't <br>
need to call htons() on it). Here is a sample routine: <br>
/* Take a service name, and a service type, and return a port number. If <br>
the <br>
service name is not found, it tries it as a decimal number. The number <br>
<br>
<br>
returned is byte ordered for the network. */ <br>
int atoport(char *service, char *proto) { <br>
int port; <br>
long int lport; <br>
struct servent *serv; <br>
char *errpos; <br>
/* First try to read it from /etc/services */ <br>
serv = getservbyname(service, proto); <br>
if (serv != NULL) <br>
port = serv->s_port; <br>
else { /* Not in services, maybe a number? */ <br>
lport = strtol(service,&errpos,0); <br>
if ( (errpos[0] != 0) || (lport < 1) || (lport > 5000) ) <br>
return -1; /* Invalid port address */ <br>
port = htons(lport); <br>
} <br>
return port; <br>
} <br>
<br>
2.4. If bind() fails, what should I do with the socket descriptor? <br>
If you are exiting, I have been assured by Andrew that all unixes will <br>
close open file descriptors on exit. If you are not exiting though, <br>
you can just close it with a regular close() call. <br>
<br>
2.5. How do I properly close a socket? <br>
This question is usually asked by people who try close(), because they <br>
have seen that that is what they are supposed to do, and then run <br>
netstat and see that their socket is still active. Yes, close() is <br>
the correct method. To read about the TIME_WAIT state, and why it is <br>
important, refer to ``2.7 Please explain the TIME_WAIT state.''. <br>
<br>
2.6. When should I use shutdown()? <br>
From Michael Hunter (mphunter@qnx.com): <br>
shutdown() is useful for deliniating when you are done providing a <br>
request to a server using TCP. A typical use is to send a request to <br>
a server followed by a shutdown(). The server will read your request <br>
followed by an EOF (read of 0 on most unix implementations). This <br>
tells the server that it has your full request. You then go read <br>
blocked on the socket. The server will process your request and send <br>
the necessary data back to you followed by a close. When you have <br>
finished reading all of the response to your request you will read an <br>
EOF thus signifying that you have the whole response. It should be <br>
noted the TTCP (TCP for Transactions -- see R. Steven's home page) <br>
provides for a better method of tcp transaction management. <br>
S.Degtyarev (deg@sunsr.inp.nsk.su) wrote a nice in-depth message to me <br>
about this. He shows a practical example of using shutdown() to aid <br>
in synchronization of client processes when one is the "reader" <br>
process, and the other is the "writer" process. A portion of his <br>
message follows: <br>
Sockets are very similar to pipes in the way they are used for data <br>
transfer and client/server transactions, but not like pipes they are <br>
bidirectional. Programs that use sockets often fork() and each <br>
process inherits the socket descriptor. In pipe based programs it is <br>
strictly recommended to close all the pipe ends that are not used to <br>
convert the pipe line to one-directional data stream to avoid data <br>
losses and deadlocks. With the socket there is no way to allow one <br>
process only to send data and the other only to receive so you should <br>
always keep in mind the consequences. <br>
Generally the difference between close() and shutdown() is: close() <br>
closes the socket id for the process but the connection is still <br>
opened if another process shares this socket id. The connection stays <br>
opened both for read and write, and sometimes this is very important. <br>
shutdown() breaks the connection for all processes sharing the socket <br>
id. Those who try to read will detect EOF, and those who try to write <br>
will reseive SIGPIPE, possibly delayed while the kernel socket buffer <br>
will be filled. Additionally, shutdown() has a second argument which <br>
denotes how to close the connection: 0 means to disable further <br>
reading, 1 to disable writing and 2 disables both. <br>
The quick example below is a fragment of a very simple client process. <br>
After establishing the connection with the server it forks. Then <br>
child sends the keyboard input to the server until EOF is received and <br>
the parent receives answers from the server. <br>
/* <br>
* Sample client fragment, <br>
* variables declarations and error handling are omitted <br>
*/ <br>
s=connect(...); <br>
if( fork() ){ /* The child, it copies its stdin to <br>
the socket */ <br>
while( gets(buffer) >0) <br>
write(s,buf,strlen(buffer)); <br>
close(s); <br>
exit(0); <br>
} <br>
else { /* The parent, it receives answers */ <br>
while( (l=read(s,buffer,sizeof(buffer)){ <br>
do_something(l,buffer); <br>
/* Connection break from the server is assumed */ <br>
/* ATTENTION: deadlock here */ <br>
wait(0); /* Wait for the child to exit */ <br>
exit(0); <br>
} <br>
What do we expect? The child detects an EOF from its stdin, it closes <br>
the socket (assuming connection break) and exits. The server in its <br>
turn detects EOF, closes connection and exits. The parent detects <br>
EOF, makes the wait() system call and exits. What do we see instead? <br>
The socket instance in the parent process is still opened for writing <br>
and reading, though the parent never writes. The server never detects <br>
EOF and waits for more data from the client forever. The parent never <br>
sees the connection is closed and hangs forever and the server hangs <br>
too. Unexpected deadlock! ( any deadlock is unexpected though :-) <br>
You should change the client fragment as follows: <br>
if( fork() ) { /* The child */ <br>
while( gets(buffer) } <br>
write(s,buffer,strlen(buffer)); <br>
shutdown(s,1); /* Break the connectio <br>
n <br>
for writing, The server will detect EOF now. Note: reading fr <br>
om <br>
the socket is still allowed. The server may send some more da <br>
ta <br>
after receiving EOF, why not? */ <br>
exit(0); <br>
} <br>
I hope this rough example explains the troubles you can have with <br>
client/server syncronization. Generally you should always remember <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -