﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-分享知识</title><link>http://www.cppblog.com/sscchh-2000/</link><description>与大家一起分享知识</description><language>zh-cn</language><lastBuildDate>Fri, 03 Apr 2026 19:54:20 GMT</lastBuildDate><pubDate>Fri, 03 Apr 2026 19:54:20 GMT</pubDate><ttl>60</ttl><item><title>关于时间的几个变量</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/12/29/16969.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Fri, 29 Dec 2006 03:07:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/12/29/16969.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/16969.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/12/29/16969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/16969.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/16969.html</trackback:ping><description><![CDATA[最近看到了关于时间上面的几个变量：timeval,time_t,tm。请了解的详细说说它们的定义和相关的调用函数，让大家一起来学习，呵呵。<img src ="http://www.cppblog.com/sscchh-2000/aggbug/16969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-12-29 11:07 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/12/29/16969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unix网络编程第三版,卷一:套接字联网API学习笔记(3)</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/17/7292.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Wed, 17 May 2006 01:42:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/17/7292.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/7292.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/17/7292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/7292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/7292.html</trackback:ping><description><![CDATA[TCP连接的建立和终止<br /><br />为了帮助我们理解conncet，accept，close这几个函数，以及使用netstat工具来调试TCP应用程序，我们必须理解TCP连接是如何建立和终止的和TCP状态转换图。<br /><br /><a name="ch02lev2sec1"></a><h4 class="docSection2Title">三次握手</h4><p class="docText">当一个TCP连接建立时，发生了以下场景：</p><a name="ch02pro01"></a><span style="FONT-WEIGHT: bold"><ol class="docList"><li><span style="FONT-WEIGHT: normal" value="1"><p class="docText">The server must be prepared to accept an incoming connection. This is normally done by calling <tt>socket</tt>, <tt>bind</tt>, and <tt>listen</tt> and is called a <span class="docEmphasis">passive open</span>.</p></span></li><li><span style="FONT-WEIGHT: normal" value="2"><p class="docText">The client issues an <span class="docEmphasis">active open</span> by calling <tt>connect</tt>. This causes the client TCP to send a "synchronize" (SYN) segment, which tells the server the client's initial sequence number for the data that the client will send on the connection. Normally, there is no data sent with the SYN; it just contains an IP header, a TCP header, and possible TCP options (which we will talk about shortly).</p></span></li><li><span style="FONT-WEIGHT: normal" value="3"><p class="docText">The server must acknowledge (ACK) the client's SYN and the server must also send its own SYN containing the initial sequence number for the data that the server will send on the connection. The server sends its SYN and the ACK of the client's SYN in a single segment.</p></span></li><li><span style="FONT-WEIGHT: normal" value="4"><p class="docText">The client must acknowledge the server's SYN.</p></span></li></ol></span><p class="docText">最少需要三次包交换，因此称作TCP的三次握手，如下图所示：<br /><a name="ch02fig02"></a>图示： TCP 的三次握手</p><p class="docText"><img height="192" alt="graphics/02fig02.gif" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/02fig02.gif" width="500" border="0" /></p><p class="docText">We show the client's initial sequence number as <span class="docEmphasis">J</span> and the server's initial sequence number as <span class="docEmphasis">K</span>. The acknowledgment number in an ACK is the next expected sequence number for the end sending the ACK. Since a SYN occupies one byte of the sequence number space, the acknowledgment number in the ACK of each SYN is the initial sequence number plus one. Similarly, the ACK of each FIN is the sequence number of the FIN plus one.</p><blockquote><p></p><p class="docList">An everyday analogy for establishing a TCP connection is the telephone system [Nemeth 1997]. The <tt>socket</tt> function is the equivalent of having a telephone to use. <tt>bind</tt> is telling other people your telephone number so that they can call you. <tt>listen</tt> is turning on the ringer so that you will hear when an incoming call arrives. <tt>connect</tt> requires that we know the other person's phone number and dial it. <tt>accept</tt> is when the person being called answers the phone. Having the client's identity returned by <tt>accept</tt> (where the identify is the client's IP address and port number) is similar to having the caller ID feature show the caller's phone number. One difference, however, is that <tt>accept</tt> returns the client's identity only after the connection has been established, whereas the caller ID feature shows the caller's phone number before we choose whether to answer the phone or not. If the DNS is used (<a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch11.html#ch11">Chapter 11</a>), it provides a service analogous to a telephone book. <tt>getaddrinfo</tt> is similar to looking up a person's phone number in the phone book. <tt>getnameinfo</tt> would be the equivalent of having a phone book sorted by telephone numbers that we could search, instead of a book sorted by name.</p><p></p></blockquote><a name="ch02lev2sec2"></a><h4 class="docSection2Title">TCP 选项</h4><h4 class="docSection2Title">Each SYN can contain TCP options. Commonly used options include the following:</h4><ul><li><p class="docText"><span class="docEmphRoman">MSS option.</span> With this option, the TCP sending the SYN announces its <span class="docEmphasis">maximum segment size</span>, the maximum amount of data that it is willing to accept in each TCP segment, on this connection. The sending TCP uses the receiver's MSS value as the maximum size of a segment that it sends. We will see how to fetch and set this TCP option with the <tt>TCP_MAXSEG</tt> socket option (<a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch07lev1sec9.html#ch07lev1sec9">Section 7.9</a>).</p></li><li><p class="docText"><span class="docEmphRoman">Window scale option.</span> The maximum window that either TCP can advertise to the other TCP is 65,535, because the corresponding field in the TCP header occupies 16 bits. But, high-speed connections, common in today's Internet (45 Mbits/sec and faster, as described in RFC 1323 [Jacobson, Braden, and Borman 1992]), or long delay paths (satellite links) require a larger window to obtain the maximum throughput possible. This newer option specifies that the advertised window in the TCP header must be scaled (left-shifted) by 0–14 bits, providing a maximum window of almost one gigabyte (65,535 x 2<sup>14</sup>). Both end-systems must support this option for the window scale to be used on a connection. We will see how to affect this option with the <tt>SO_RCVBUF</tt> socket option (<a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch07lev1sec5.html#ch07lev1sec5">Section 7.5</a>).</p><blockquote><p></p><p class="docList">To provide interoperability with older implementations that do not support this option, the following rules apply. TCP can send the option with its SYN as part of an active open. But, it can scale its windows only if the other end also sends the option with its SYN. Similarly, the server's TCP can send this option only if it receives the option with the client's SYN. This logic assumes that implementations ignore options that they do not understand, which is required and common, but unfortunately, not guaranteed with all implementations.</p><p></p></blockquote></li><li><p class="docText"><span class="docEmphRoman">Timestamp option.</span> This option is needed for high-speed connections to prevent possible data corruption caused by old, delayed, or duplicated segments. Since it is a newer option, it is negotiated similarly to the window scale option. As network programmers there is nothing we need to worry about with this option.</p></li></ul><p class="docText">These common options are supported by most implementations. The latter two are sometimes called the "RFC 1323 options," as that RFC [Jacobson, Braden, and Borman 1992] specifies the options. They are also called the "long fat pipe options," since a network with either a high bandwidth or a long delay is called a <span class="docEmphasis">long fat pipe</span>. Chapter 24 of TCPv1 contains more details on these options.</p><a name="ch02lev2sec3"></a><h4 class="docSection2Title">TCP 连接的终止</h4><p class="docText">TCP建立时需要三次通知，而终止一个TCP连接时需要四次通知。<br /><a name="ch02pro02"></a><span style="FONT-WEIGHT: bold"><span style="FONT-WEIGHT: normal" value="1">One application calls <tt>close</tt> first, and we say that this end performs the <span class="docEmphasis">active close</span>. This end's TCP sends a FIN segment, which means it is finished sending data.</span></span></p><ol class="docList"><li><span style="FONT-WEIGHT: normal" value="2"><p class="docText">The other end that receives the FIN performs the <span class="docEmphasis">passive close</span>. The received FIN is acknowledged by TCP. The receipt of the FIN is also passed to the application as an end-of-file (after any data that may have already been queued for the application to receive), since the receipt of the FIN means the application will not receive any additional data on the connection.</p></span></li><li><span style="FONT-WEIGHT: normal" value="3"><p class="docText">Sometime later, the application that received the end-of-file will <tt>close</tt> its socket. This causes its TCP to send a FIN.</p></span></li><li><span style="FONT-WEIGHT: normal" value="4"><p class="docText">The TCP on the system that receives this final FIN (the end that did the active close) acknowledges the FIN.</p></span></li></ol><p class="docText">Since a FIN and an ACK are required in each direction, four segments are normally required. We use the qualifier "normally" because in some scenarios, the FIN in Step 1 is sent with data. Also, the segments in Steps 2 and 3 are both from the end performing the passive close and could be combined into one segment. We show these packets in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch02lev1sec6.html#ch02fig03">Figure 2.3</a>.</p><center><h5 class="docFigureTitle"><a name="ch02fig03"></a>Figure 2.3. Packets exchanged when a TCP connection is closed.</h5><p class="docText"><img height="241" alt="graphics/02fig03.gif" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/02fig03.gif" width="500" border="0" /></p></center><p class="docText">A FIN occupies one byte of sequence number space just like a SYN. Therefore, the ACK of each FIN is the sequence number of the FIN plus one.</p><p class="docText">Between Steps 2 and 3 it is possible for data to flow from the end doing the passive close to the end doing the active close. This is called a <span class="docEmphasis">half-close</span> and we will talk about this in detail with the <tt>shutdown</tt> function in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch06lev1sec6.html#ch06lev1sec6">Section 6.6</a>.</p><p class="docText">The sending of each FIN occurs when a socket is closed. We indicated that the application calls <tt>close</tt> for this to happen, but realize that when a Unix process terminates, either voluntarily (calling <tt>exit</tt> or having the <tt>main</tt> function return) or involuntarily (receiving a signal that terminates the process), all open descriptors are closed, which will also cause a FIN to be sent on any TCP connection that is still open.</p><p class="docText">Although we show the client in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch02lev1sec6.html#ch02fig03">Figure 2.3</a> performing the active close, either end—the client or the server—can perform the active close. Often the client performs the active close, but with some protocols (notably HTTP/1.0), the server performs the active close.</p><a name="ch02lev2sec4"></a><h4 class="docSection2Title">TCP 状态转换图</h4><p class="docText">关于TCP连接的建立和终止操作可以由一个状态转换图来详细说明，如下图所示：<br /><a name="ch02fig04"></a>图示：TCP 状态转换图<br /><img height="636" alt="graphics/02fig04.gif" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/02fig04.gif" width="500" border="0" /></p><p class="docText">There are 11 different states defined for a connection and the rules of TCP dictate the transitions from one state to another, based on the current state and the segment received in that state. For example, if an application performs an active open in the CLOSED state, TCP sends a SYN and the new state is SYN_SENT. If TCP next receives a SYN with an ACK, it sends an ACK and the new state is ESTABLISHED. This final state is where most data transfer occurs.</p><p class="docText">The two arrows leading from the ESTABLISHED state deal with the termination of a connection. If an application calls <tt>close</tt> before receiving a FIN (an active close), the transition is to the FIN_WAIT_1 state. But if an application receives a FIN while in the ESTABLISHED state (a passive close), the transition is to the CLOSE_WAIT state.</p><p class="docText">We denote the normal client transitions with a darker solid line and the normal server transitions with a darker dashed line. We also note that there are two transitions that we have not talked about: a simultaneous open (when both ends send SYNs at about the same time and the SYNs cross in the network) and a simultaneous close (when both ends send FINs at the same time). Chapter 18 of TCPv1 contains examples and a discussion of both scenarios, which are possible but rare.</p><p class="docText">One reason for showing the state transition diagram is to show the 11 TCP states with their names. These states are displayed by <tt>netstat</tt>, which is a useful tool when debugging client/server applications. We will use <tt>netstat</tt> to monitor state changes in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch05.html#ch05">Chapter 5</a>.</p><a name="ch02lev2sec5"></a><h4 class="docSection2Title">观察包（Watching the Packets）</h4><p class="docText">下土显示了一个TCP连接实际发生的包交换情况：连接建立，数据传输和连接终止。在每一端传输的时候，也给出了TCP状态。 <br /><a name="ch02fig05"></a>TCP 连接的包交换</p><p class="docText"><img height="414" alt="graphics/02fig05.gif" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/02fig05.gif" width="478" border="0" /></p><p class="docText">The client in this example announces an MSS of 536 (indicating that it implements only the minimum reassembly buffer size) and the server announces an MSS of 1,460 (typical for IPv4 on an Ethernet). It is okay for the MSS to be different in each direction (see <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch02lev1sec15.html#ch02lev1sec15">Exercise 2.5</a>).</p><p class="docText">Once a connection is established, the client forms a request and sends it to the server. We assume this request fits into a single TCP segment (i.e., less than 1,460 bytes given the server's announced MSS). The server processes the request and sends a reply, and we assume that the reply fits in a single segment (less than 536 in this example). We show both data segments as bolder arrows. Notice that the acknowledgment of the client's request is sent with the server's reply. This is called <span class="docEmphasis">piggybacking</span> and will normally happen when the time it takes the server to process the request and generate the reply is less than around 200 ms. If the server takes longer, say one second, we would see the acknowledgment followed later by the reply. (The dynamics of TCP data flow are covered in detail in Chapters 19 and 20 of TCPv1.)</p><p class="docText">We then show the four segments that terminate the connection. Notice that the end that performs the active close (the client in this scenario) enters the TIME_WAIT state. We will discuss this in the next section.</p><p class="docText">It is important to notice in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch02lev1sec6.html#ch02fig05">Figure 2.5</a> that if the entire purpose of this connection was to send a one-segment request and receive a one-segment reply, there would be eight segments of overhead involved when using TCP. If UDP was used instead, only two packets would be exchanged: the request and the reply. But switching from TCP to UDP removes all the reliability that TCP provides to the application, pushing lots of these details from the transport layer (TCP) to the UDP application. Another important feature provided by TCP is congestion control, which must then be handled by the UDP application. Nevertheless, it is important to understand that many applications are built using UDP because the application exchanges small amounts of data and UDP avoids the overhead of TCP connection establishment and connection termination.</p><a href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_22961534.html"><img height="1" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/pixel.gif" width="1" border="0" /></a><h3 class="docSection1Title">TIME_WAIT 状态</h3><h3 class="docSection1Title">毫无疑问，关于网络编程中最让人误解点之一就是 TIME_WAIT 状态。 在一端调用了close之后，该端维持这个状态的时间为两倍最大段生存时间（<span class="docEmphasis">maximum segment lifetime</span> (MSL)）。</h3><p class="docText">Every implementation of TCP must choose a value for the MSL. The recommended value in RFC 1122 [Braden 1989] is 2 minutes, although Berkeley-derived implementations have traditionally used a value of 30 seconds instead. This means the duration of the TIME_WAIT state is between 1 and 4 minutes. The MSL is the maximum amount of time that any given IP datagram can live in a network. We know this time is bounded because every datagram contains an 8-bit hop limit (the IPv4 TTL field in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_app01lev1sec2.html#app01fig01">Figure A.1</a> and the IPv6 hop limit field in <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_app01lev1sec3.html#app01fig02">Figure A.2</a>) with a maximum value of 255. Although this is a hop limit and not a true time limit, the assumption is made that a packet with the maximum hop limit of 255 cannot exist in a network for more than MSL seconds.</p><p class="docText">The way in which a packet gets "lost" in a network is usually the result of routing anomalies. A router crashes or a link between two routers goes down and it takes the routing protocols seconds or minutes to stabilize and find an alternate path. During that time period, routing loops can occur (router A sends packets to router B, and B sends them back to A) and packets can get caught in these loops. In the meantime, assuming the lost packet is a TCP segment, the sending TCP times out and retransmits the packet, and the retransmitted packet gets to the final destination by some alternate path. But sometime later (up to MSL seconds after the lost packet started on its journey), the routing loop is corrected and the packet that was lost in the loop is sent to the final destination. This original packet is called a <span class="docEmphasis">lost duplicate</span> or a <span class="docEmphasis">wandering duplicate</span>. TCP must handle these duplicates.</p><p class="docText">There are two reasons for the TIME_WAIT state:</p><span style="FONT-WEIGHT: bold"><ol class="docList" type="1"><li><span style="FONT-WEIGHT: normal"><p class="docList">To implement TCP's full-duplex connection termination reliably</p></span></li><li><span style="FONT-WEIGHT: normal"><p class="docList">To allow old duplicate segments to expire in the network</p></span></li></ol></span><p class="docText">The first reason can be explained by looking at <a class="docLink" href="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_ch02lev1sec6.html#ch02fig05">Figure 2.5</a> and assuming that the final ACK is lost. The server will resend its final FIN, so the client must maintain state information, allowing it to resend the final ACK. If it did not maintain this information, it would respond with an RST (a different type of TCP segment), which would be interpreted by the server as an error. If TCP is performing all the work necessary to terminate both directions of data flow cleanly for a connection (its full-duplex close), then it must correctly handle the loss of any of these four segments. This example also shows why the end that performs the active close is the end that remains in the TIME_WAIT state: because that end is the one that might have to retransmit the final ACK.</p><p class="docText">To understand the second reason for the TIME_WAIT state, assume we have a TCP connection between 12.106.32.254 port 1500 and 206.168.112.219 port 21. This connection is closed and then sometime later, we establish another connection between the same IP addresses and ports: 12.106.32.254 port 1500 and 206.168.112.219 port 21. This latter connection is called an <span class="docEmphasis">incarnation</span> of the previous connection since the IP addresses and ports are the same. TCP must prevent old duplicates from a connection from reappearing at some later time and being misinterpreted as belonging to a new incarnation of the same connection. To do this, TCP will not initiate a new incarnation of a connection that is currently in the TIME_WAIT state. Since the duration of the TIME_WAIT state is twice the MSL, this allows MSL seconds for a packet in one direction to be lost, and another MSL seconds for the reply to be lost. By enforcing this rule, we are guaranteed that when we successfully establish a TCP connection, all old duplicates from previous incarnations of the connection have expired in the network.</p><blockquote><p></p><p class="docList">There is an exception to this rule. Berkeley-derived implementations will initiate a new incarnation of a connection that is currently in the TIME_WAIT state if the arriving SYN has a sequence number that is "greater than" the ending sequence number from the previous incarnation. Pages 958–959 of TCPv2 talk about this in more detail. This requires the server to perform the active close, since the TIME_WAIT state must exist on the end that receives the next SYN. This capability is used by the <tt>rsh</tt> command. RFC 1185 [Jacobson, Braden, and Zhang 1990] talks about some pitfalls in doing this.</p><p></p><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td valign="top"><h3 class="docSection1Title" id="225793-970">一般网络程序所使用的协议</h3><p class="docText">下图总结了一些：</p><center><h5 class="docFigureTitle"><a name="ch02fig19"></a>Figure 2.19. Protocol usage of various common Internet applications.</h5><p class="docText"><img id="129022115118" height="454" alt="graphics/02fig19.gif" src="mk:@MSITStore:E:\正在看的书籍\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/02fig19.gif" width="500" border="0" /></p></center><p class="docText">The first two applications, <tt>ping</tt> and <tt>traceroute</tt>, are diagnostic applications that use ICMP. <tt>traceroute</tt> builds its own UDP packets to send and reads ICMP replies.</p><p class="docText">The three popular routing protocols demonstrate the variety of transport protocols used by routing protocols. OSPF uses IP directly, employing a raw socket, while RIP uses UDP and BGP uses TCP.</p><p class="docText">The next five are UDP-based applications, followed by seven TCP applications and four that use both UDP and TCP. The final five are IP telephony applications that use SCTP exclusively or optionally UDP, TCP, or SCTP.</p></td></tr></tbody></table></blockquote><img src ="http://www.cppblog.com/sscchh-2000/aggbug/7292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-17 09:42 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/17/7292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>母亲节快到了，写点东西送给母亲</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/12/7011.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Fri, 12 May 2006 06:10:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/12/7011.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/7011.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/12/7011.html#Feedback</comments><slash:comments>20</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/7011.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/7011.html</trackback:ping><description><![CDATA[      母亲节快到了，独自在外求学的我，想给母亲送点礼物。小时候的记忆中，母亲是一个很严厉的人，记得有两次被母亲狠狠的揍了。一次是我丢了一块手表，那时候我还上小学，就偷偷的把母亲的手表带到学校，结果给弄丢了。还有一次就是和伙伴玩，结果不知道什么原因和他打架了，又被狠狠的揍了一顿。那时候心里想，我现在还小，等长大了母亲就打不过我了。一晃10几年过去了，我还有一年就毕业了。在这段时间里，我深深体会到了母亲的爱和关怀。<br />      2000年那年，我考上了吉林大学，母亲哭了。我想母亲也是和我一样，期待着这个梦想，而真正实现了的时候，我们都抑制不了那个喜悦的心情。我想母亲一定感到很幸福，她会感到很骄傲的。可能有些人会想，考了大学有什么了不起的，现在的大学生跟民工一样，到处都是。也没有什么好骄傲的吧。可是，在这里我要告诉你，我们那个村，甚至那个乡，在我的记忆中，就出来这样一个大学生，那已经是上个世纪六七十年代的事情了，也就是在中间隔了近30年了。你可以想象那样的场景。母亲能不骄傲嘛？其实母亲的管教现在想来，不是逼着让我学习，而是让我自由的发展，说起来也怪，小时候我可是一个非常调皮的孩子，整天和伙伴们玩的很疯。到处下河捉鱼，上树掏鸟窝。凡是能玩的都玩了。这可能跟母亲的言传身教有关系的。表姐也曾问过我：“小时候大家都是一起玩的，甚至比我还用功，怎么我没有考上大学你去考上了呢？”我也开玩笑的回答：其实我玩的时候，头脑还是在思考东西呢。其实表姐也是一个很优秀的，只是由于家庭的原因，实在太穷了，上完了初中就没有上学了。说到这里，其实在我们村里，或者任何一个贫穷的农村，我们这些孩子不是笨，而是真正由于家里孩子多，又非常贫穷，又要让每个孩子都能读点书，认上几个字。所以大部分的人都只能读到初中甚至小学没有毕业就辍学了。所以我觉得母亲难能可贵的，就是她的坚持，因为在我初三那年毕业的时候，由于考试成绩不理想，要读高中还需要交五千块钱的扩招费。那个时候真是非常艰难的一步。真可以用摔锅卖铁来形容。所以我很感谢母亲在那么困难的时候能够咬牙撑过来了。当然在这里还要感谢我的干爸干妈。没有他们的大力支持我也很难走到这一步。<br />      9月份，我离开了生我养我的那个贫瘠的农村，临走的时候，我怀揣着八千块钱踏往长春的列车上。八千块钱里面现在还清楚的记得：叔叔借的两千，舅舅借的一千，表哥借的一千五，还有姨哥借的一块和姨姐借的五百。剩下的两千是亲朋好友来和喜酒给的。从此开始了我在长春的求学之路。也就是我来到长春之后的两个月左右，父亲和母亲也去了上海。目的就是打工给我挣来年的学费。要知道亲戚家里的生活也并不好，能支助我这么多钱读书实在不易了。下一年的学费当然不可能，也不好意思张口了。先开始说说我的父母吧，来到了上海，他们真的不容易。在老乡的帮助下，很快父母便开始了第一份工作。母亲在一个菜市场里面帮别人卖鸡鸭，家禽等，一个月500块钱。说起来这个可能看上去并不怎么太辛苦。但是我要说这个工作我母亲咬牙坚持了两个月最终辞去了。为什么呢？母亲每天早上4点就起床，然后到菜市场去，这个时候有一车货，由于菜市场是在二楼，母亲（还有另外一个阿姨，生活也一定不易，否则根本不可能来这个地方）他们俩就一个又一个满载家禽的篮子往二楼上面爬。这样一个多小时候之后就开始给店主卖，然后把一只又一只的家禽宰杀，然后去皮，洗干净。就这样一段时间，母亲整个人肿的不成样子了，手皮退了一层又一层。因为实在挺不住了，去医院治疗。结果辛苦挣了一点钱几乎都用在了医疗费上面了。再来说说父亲吧，父亲的第一份工作是送货，就是那个脚蹬三轮车，每天送好几次，每次有好几百斤，有时候能达到上千斤。一个月也就六七百块钱。就这样也挺了几个月便辞了。我还有一个妹妹，父母这次外出打工，不仅仅是为了我一个人的求学。因为我妹妹也高一了，父母不仅仅要供我一个人。<br />      来到了长春，一切都是那么新奇，看到了大学生活真的是太自由了。没有老师的管束。也许是我的理想，也许是这来之易的求学机会，我仍然想在高中那样，努力学习，因为我的理想是要让父母过上幸福的生活，不再那么操劳。让乡村们都能够过上幸福的生活。所以我必须努力学习，来学习到真正的本领，这样才有希望。让我意外的是，第一年结束之后，我竟然获得了奖助学金共5700块钱。还记得当时我简直不敢相信这是真的。这可是需要母亲日日夜夜拼命挣上一年啊！我不知道该说什么好，只能感谢学校对我的关怀。就这样，或许是受到了激励，或许我真的很优秀。整个大学四年我一共获得了奖助学金共26，000块钱（其中奖学金12，000）。再加上中国工商银行贷款14，000。使我顺利的完成了大学四年的学业。除了学业之外。我还用一部分钱支助我妹妹读书。另外由于爷爷奶奶年纪大了，爸妈他们又不在身边。我也给他们寄过几次生活费。还记着最多一次是500，那时候爷爷生病了，需要住院。此外由于爸妈在外打工，大姑他们给我家种地。我也寄过几百块钱。同时也算是减轻了爸妈他们的一点负担吧。整个大学生活过得很充实，更让我幸运的是，遇到了一个对我有知遇之恩的老师，也就是我现在的导师陈老师，他对我生活和学习上的帮助让我感激不尽；而且我还遇到了一个通情达理，艰苦朴素而又十分漂亮的女孩，也就是我的女朋友霖霖，这几年来真的很感谢她的理解和支持。<br />      不但我获得了这么多的幸运。我的妹妹也是幸运的。由于我在学校和国家的支助下完成了学业，我爸妈辛苦挣的钱就能够供我妹妹读书了。现在我妹妹已经快毕业了，目前在实习中，虽然每月900块钱，但也是相当不错了。而是现在还有一年就毕业了，由于比较幸运，读的是公费。每个月还能有八九百块钱的生活补助。从而能让父母他们不要那么操劳了。<br />      可是，就在前两天，我爸爸跟我说我母亲又去介绍所花了100块钱找了一份工作。母亲的工作是给一家医院洗菜，刷碗，打杂什么的。一个月700块钱，每天早上六点到晚上九点。我昨天晚上给母亲打了一个电话，等到快九点半才找到母亲的。我坚决要求母亲辞掉工作，可是母亲就说闲着浑身也是疼，还不如忙点呢。一个小时还不到2块钱，母亲还是那样的乐观。我真的不知道怎么样劝才能劝她辞掉这份工作。<br />      其实母亲的身体并不好，在我上高中的时候，母亲下地干活累出了肝炎，最后总算治好了，但是也不能太劳累。而且母亲现在还有子宫肌瘤，虽然是良性的，但是也总出血带来了身体的严重贫血。我婶婶跟我说：“你妈有病你和你妹妹怎么不让她治啊，别人有病都治，她有病留着，真是奇怪。”其实我妈也想治，不过却说：“等你俩上班挣钱了再治，现在去医院也检查了，说不要紧，而且手术费也得六七千，根本也没有钱治。”，一个人的力量真的是那么的微弱啊。我只能盼望我早点毕业，去挣钱给母亲治病。我在这里要说：“妈，我爱你，是你的坚强支撑了这个家庭，让我们感到了您伟大的母爱！”。<br />      看到了我的故事，我希望每一个向我这样的穷乡娃都能够有一颗奋斗的心，来改变我们的生活。都能够深爱着自己的母亲，能够期待着明天美好的生活...<img src ="http://www.cppblog.com/sscchh-2000/aggbug/7011.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-12 14:10 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/12/7011.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unix网络编程第三版,卷一:套接字联网API学习笔记(2)</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/10/6860.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Wed, 10 May 2006 03:13:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/10/6860.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6860.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/10/6860.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6860.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6860.html</trackback:ping><description><![CDATA[
		<p>该节主要展示一个简单的[日期时间]服务器的程序示例.<br />§1.3 一个简单的日期时间服务器程序代码<br />   这个服务器程序可以为上一节的客户端提供服务。<br /></p>
		<pre> 1 #include     "unp.h"<br />
 2 #include     &lt;time.h&gt;<br />

 3 int<br />
 4 main(int argc, char **argv)<br />
 5 {<br />
 6     int     listenfd, connfd;<br />
 7     struct sockaddr_in servaddr;<br />
 8     char    buff[MAXLINE];<br />
 9     time_t ticks;<br />

10     listenfd = Socket(AF_INET, SOCK_STREAM, 0);<br />

11     bzeros(&amp;servaddr, sizeof(servaddr));<br />
12     servaddr.sin_family = AF_INET;<br />
13     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);<br />
14     servaddr.sin_port = htons(13); /* daytime server */<br />

15     Bind(listenfd, (SA *) &amp;servaddr, sizeof(servaddr));<br />

16     Listen(listenfd, LISTENQ);<br />

17     for ( ; ; ) {<br />
18         connfd = Accept(listenfd, (SA *) NULL, NULL);<br />

19         ticks = time(NULL);<br />
20         snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&amp;ticks));<br />
21         Write(connfd, buff, strlen(buff));<br />

22         Close(connfd);<br />
23     }<br />
24 }<br /></pre>
		<a name="ch01lev3sec8">
		</a>
		<h4 class="docSection2Title">产生一个TCP套接字</h4>
		<h4 class="docSection2Title">
				<span class="docEmphasis">
						<tt>10</tt>
				</span>创建一个TCP套接字，与客户端一样。</h4>
		<h4 class="docSection2Title">
				<a name="ch01lev3sec9">
				</a>绑定服务器的广为人知的端口到该套接字</h4>
		<p class="docText">
				<span class="docEmphasis">
						<tt>11–15</tt>
				</span>服务器通过填充网络套接字结构体中的端口域，以及服务器的网络接口（IP地址），然后进行绑定（调用bind）。在这里指定IP地址为INADDR_ANY，为了让客户端可以连接服务器的任一网络接口（因为服务器可能有多块网卡，也就对应了多个IP地址），也就是说如果服务器有两个IP地址，客户端连接任一IP地址即可。后续章节中介绍了如何限制客户端连接到一个固定的接口上。</p>
		<a name="ch01lev3sec10">
		</a>
		<h4 class="docSection2Title">转换为监听套接字</h4>
		<p class="docText">
				<span class="docEmphasis">
						<tt>16</tt>
				</span>通过调用listen，一个套接字就转换为监听套接字，这就是说该套接字负责接收来自客户端的连接请求，而并不真正与客户端进行信息传输。<br />常量<tt>LISTENQ</tt> 是在头文件<tt>unp.h中定义的，它是指能够同时监听客户端连接的个数。不超过LISTENQ的客户端同时连接服务器，它们会在一个队列中排队，来等待服务器的处理。后续章节有更详细的讨论。<br /></tt><br />接收客户端连接，发送回复</p>
		<p class="docText">
				<span class="docEmphasis">
						<tt>17–21</tt>
				</span>一般地，服务器进程在调用accept之后进入到睡眠状态，等待着客户端地连接请求. 一个TCP连接通过一个称为三方握手来建立，当三方握手完成之后，accept调用返回。返回值是一个新的套接字描述符（一个整数值connfd），这个新的套接字负责与客户端进行通讯。对于每一个客户端地连接，accept都返回一个新的套接字描述符。整本书使用的无限循环风格是这样的：</p>
		<blockquote>
				<pre>
				</pre>
				<pre>for ( ; ; ) {
    . . .
}
</pre>
				<pre>
				</pre>
		</blockquote>
		<p class="docText">当前时间和日期通过调用库函数time来获得，并且通过调用ctime进行转换，使得我们能够直观的阅读。如下：<br />Mon May 26 20:58:40 2003</p>
		<p>
		</p>
		<a name="ch01lev3sec12">
		</a>
		<h4 class="docSection2Title">终止连接</h4>
		<p class="docText">
				<span class="docEmphasis">
						<tt>22</tt>
				</span>客户端调用close之后，服务器关闭连接。这时候引起了一个TCP连接终止序列：一个FIN发送到每一端，同时每一个FIN都要被另一端确认。在后面章节中将会对TCP连接建立时候的三方握手以及TCP连接终止时候的四包交换有更详细的讨论。<br />   以上给出的客户端和服务器版本都是协议相关的（IPv4），在后面将会给出一个协议无关的版本（IPv4和IPv6都适用，主要通过使用getaddrinfo函数）。<br />   最后需要补充的一点是，在以上涉及到Socket API调用的时候，每个函数的第一个字母变成了大写，其意义和小写开头的是一样的，只不过多了一个错误处理罢了。</p>
<img src ="http://www.cppblog.com/sscchh-2000/aggbug/6860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-10 11:13 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/10/6860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>err_开头的自定义函数</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6838.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Tue, 09 May 2006 13:39:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6838.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6838.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6838.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6838.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6838.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td valign="top">
										<h3 class="docSection1Title" id="162666-841">D.3 Standard Error Functions</h3>
										<p class="docText">We define our own set of error functions that are used throughout the text to<br /> handle error conditions. The reason for using our own error functions is to <br />let us write our error handling with a single line of C code, as in</p>
										<pre>
										</pre>
										<pre>if <span class="docEmphasis">(error condition)</span>
    err_sys <span class="docEmphasis">(printf format with any number of arguments)</span>;
</pre>
										<pre>
										</pre>
										<p class="docText">instead of</p>
										<pre>
										</pre>
										<pre>if <span class="docEmphasis">(error condition)</span> {
    char buff [2002];
    snprintf(buff, sizeof (buff), <span class="docEmphasis">printf format <br />    with any number of arguments)</span>;
    perror(buff);
    exit (1);
}
</pre>
										<pre>
										</pre>
										<p class="docText">Our error functions use the variable-length argument list facility from <tt>ANSI C</tt>. <br />See Section 7.3 of [Kernighan and Ritchie 1988] for additional details.</p>
										<p class="docText">
												<a class="docLink" href="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_app04lev1sec3.html#app04fig03">
														<font color="#002c99">Figure D.3</font>
												</a>lists the differences between the various error functions. <br />If the global integer <tt>daemon_proc</tt> is nonzero, the message is passed to<br /><tt>syslog</tt> with the indicated level; otherwise, the error is output to standard error.<br />Figure D.3. Summary of our standard error functions.<br /><img id="132235130214" height="138" alt="graphics/xdfig03.gif" src="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/xdfig03.gif" width="367" border="0" /></p>
										<p class="docText">
												<a class="docLink" href="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_app04lev1sec3.html#app04fig04">
														<font color="#002c99">Figure D.4</font>
												</a>shows the first five functions from <a class="docLink" href="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/0131411551_app04lev1sec3.html#app04fig03"><font color="#002c99">Figure D.3</font></a>.</p>
										<h5 class="docExampleTitle">
												<a name="app04fig04">
												</a>Figure D.4 Our standard error functions.</h5>
										<p class="docText">
												<span class="docEmphasis">lib/error.c</span>
										</p>
										<pre> 1 #include    "unp.h"
 2 #include    &lt;stdarg.h&gt;          /* ANSI C header file */
 3 #include    &lt;syslog.h&gt;          /* for syslog() */

 4 int     daemon_proc;            /* set nonzero by daemon_init() */

 5 static void err_doit(int, int, const char *, va_list);

 6 /* Nonfatal error related to system call
 7  * Print message and return */

 8 void
 9 err_ret(const char *fmt, ...)
10 {
11     va_list ap;

12     va_start(ap, fmt);
13     err_doit(1, LOG_INFO, fmt, ap);
14     va_end(ap);
15     return;
16 }

17 /* Fatal error related to system call
18  * Print message and terminate */

19 void
20 err_sys(const char *fmt, ...)
21 {
22     va_list ap;

23     va_start(ap, fmt);
24     err_doit(1, LOG_ERR, fmt, ap);
25     va_end(ap);
26     exit(1);
27 }

28 /* Fatal error related to system call
29  * Print message, dump core, and terminate */

30 void
31 err_dump(const char *fmt, ...)
32 {
33     va_list ap;

34     va_start(ap, fmt);
35     err_doit(1, LOG_ERR, fmt, ap);
36     va_end(ap);
37     abort();                    /* dump core and terminate */
38     exit(1);                    /* shouldn't get here */
39 }

40 /* Nonfatal error unrelated to system call
41  * Print message and return */

42 void
43 err_msg(const char *fmt, ...)
44 {
45     va_list ap;

46     va_start(ap, fmt);
47     err_doit(0, LOG_INFO, fmt, ap);
48     va_end(ap);
49     return;
50 }

51 /* Fatal error unrelated to system call
52  * Print message and terminate */

53 void
54 err_quit(const char *fmt, ...)
55 {
56     va_list ap;

57     va_start(ap, fmt);
58     err_doit(0, LOG_ERR, fmt, ap);

59     va_end(ap);
60     exit(1);
61 }

62 /* Print message and return to caller
63  * Caller specifies "errnoflag" and "level" */

64 static void
65 err_doit(int errnoflag, int level, const char *fmt, va_list ap)
66 {
67     int     errno_save, n;
68     char    buf[MAXLINE + 1];

69     errno_save = errno;         /* value caller might want printed */
70 #ifdef HAVE_VSNPRINTF
71     vsnprintf(buf, MAXLINE, fmt, ap);   * safe */
72 #else
73     vsprintf(buf, fmt, ap);     /* not safe */
74 #endif
75     n = strlen(buf);
76     if (errnoflag)
77         snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
78     strcat(buf, "\n");

79     if (daemon_proc) {
80         syslog(level, buf);
81     } else {
82         fflush(stdout);         /* in case stdout and stderr are the same */
83         fputs(buf, stderr);
84         fflush(stderr);
85     }
86     return;
87 }
</pre>
										<ul>
										</ul>
								</td>
						</tr>
				</tbody>
		</table>
		<td>
		</td>
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="tt1">
										<font color="#002c99">
										</font>
								</td>
								<td class="tt1" valign="top" align="right">
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/sscchh-2000/aggbug/6838.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-09 21:39 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6838.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>unp.h文件内容</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6836.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Tue, 09 May 2006 12:43:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6836.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6836.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6836.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6836.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6836.html</trackback:ping><description><![CDATA[
		<pre>  1 /* Our own header. Tabs are set for 4 spaces, not 8 */
 
  2 #ifndef __unp_h
  3 #define __unp_h

  4 #include    "../config.h"      /* configuration options for current OS */
  5                            /* "../config.h" is generated by configure */

  6 /* If anything changes in the following list of #includes, must change
  7    acsite.m4 also, for configure's tests. */

  8 #include    &lt;sys/types.h&gt;       /* basic system data types */
  9 #include    &lt;sys/socket.h&gt;      /* basic socket definitions */
 10 #include    &lt;sys/time.h&gt;        /* timeval{} for select() */
 11 #include    &lt;time.h&gt;            /* timespec{} for pselect() */
 12 #include    &lt;netinet/in.h&gt;      /* sockaddr_in{} and other Internet defns */
 13 #include    &lt;arpa/inet.h&gt;       /* inet(3) functions */
 14 #include    &lt;errno.h&gt;
 15 #include    &lt;fcntl.h&gt;           /* for nonblocking */
 16 #include    &lt;netdb.h&gt;
 17 #include    &lt;signal.h&gt;
 18 #include    &lt;stdio.h&gt;
 19 #include    &lt;stdlib.h&gt;
 20 #include    &lt;string.h&gt;
 21 #include    &lt;sys/stat.h&gt;        /* for S_xxx file mode constants */
 22 #include    &lt;sys/uio.h&gt;         /* for iovec{} and readv/writev */
 23 #include    &lt;unistd.h&gt;
 24 #include    &lt;sys/wait.h&gt;
 25 #include    &lt;sys/un.h&gt;          /* for Unix domain sockets */

 26 #ifdef  HAVE_SYS_SELECT_H
 27 # include   &lt;sys/select.h&gt;      /* for convenience */
 28 #endif

 29 #ifdef  HAVE_SYS_SYSCTL_H
 30 # include   &lt;sys/sysctl.h&gt;
 31 #endif

 32 #ifdef  HAVE_POLL_H
 33 # include  &lt;poll.h&gt;             /* for convenience */
 34 #endif

 35 #ifdef  HAVE_SYS_EVENT_H
 36 # include   &lt;sys/event.h&gt;       /* for kqueue */
 37 #endif

 38 #ifdef  HAVE_STRINGS_H
 39 # include   &lt;strings.h&gt;         /* for convenience */
 40 #endif

 41 /* Three headers are normally needed for socket/file ioctl's:
 42  * &lt;sys/ioctl.h&gt;, &lt;sys/filio.h&gt;, and &lt;sys/sockio.h&gt;.
 43  */
 44 #ifdef  HAVE_SYS_IOCTL_H
 45 # include   &lt;sys/ioctl.h&gt;
 46 #endif
 47 #ifdef  HAVE_SYS_FILIO_H
 48 # include   &lt;sys/filio.h&gt;
 49 #endif
 50 #ifdef  HAVE_SYS_SOCKIO_H
 51 # include   &lt;sys/sockio.h&gt;
 52 #endif

 53 #ifdef  HAVE_PTHREAD_H
 54 # include   &lt;pthread.h&gt;
 55 #endif

 56 #ifdef  HAVE_NET_IF_DL_H
 57 # include    &lt;net/if_dl.h&gt;
 58 #endif

 59 #ifdef  HAVE_NETINET_SCTP_H
 60 #include     &lt;netinet/sctp.h&gt;
 61 #endif

 62 /* OSF/1 actually disables recv() and send() in &lt;sys/socket.h&gt; */
 63 #ifdef  __osf__
 64 #undef  recv
 65 #undef  send
 66 #define recv(a,b,c,d)   recvfrom(a,b,c,d,0,0)
 67 #define send(a,b,c,d)   sendto(a,b,c,d,0,0)
 68 #endif

 69 #ifndef INADDR_NONE
 70 #define INADDR_NONE 0xffffffff  /* should have been in &lt;netinet/in.h&gt; */
 71 #endif

 72 #ifndef SHUT_RD                 /* these three POSIX names are new */
 73 #define SHUT_RD     0           /* shutdown for reading */
 74 #define SHUT_WR     1           /* shutdown for writing */
 75 #define SHUT_RDWR   2           /* shutdown for reading and writing */
 76 #endif

 77 #ifndef INET_ADDRSTRLEN
 78 #define INET_ADDRSTRLEN     16  /* "ddd.ddd.ddd.ddd\0"
 79                                    1234567890123456 */
 80 #endif

 81 /* Define following even if IPv6 not supported, so we can always allocate
 82    an adequately sized buffer without #ifdefs in the code. */
 83 #ifndef INET6_ADDRSTRLEN
 84 #define INET6_ADDRSTRLEN    46  /* max size of IPv6 address string:
 85                    "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx" or
 86                    "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd\0"
 87                     1234567890123456789012345678901234567890123456 */
 88 #endif

 89 /* Define bzero() as a macro if it's not in standard C library. */
 90 #ifndef HAVE_BZERO
 91 #define bzero(ptr,n)        memset (ptr, 0, n)
 92 #endif

 93 /* Older resolvers do not have gethostbyname2() */
 94 #ifndef HAVE_GETHOSTBYNAME2
 95 #define gethostbyname2(host,family)     gethostbyname((host))
 96 #endif

 97 /* The structure returned by recvfrom_flags() */
 98 struct unp_in_pktinfo {
 99     struct in_addr ipi_addr;    /* dst IPv4 address */
100     int     ipi_ifindex;        /* received interface index */
101 };

102 /* We need the newer CMSG_LEN() and CMSG_SPACE() macros, but few
103    implementations support them today. These two macros really need
104     an ALIGN() macro, but each implementation does this differently. */
105 #ifndef CMSG_LEN
106 #define CMSG_LEN(size)      (sizeof(struct cmsghdr) + (size))
107 #endif
108 #ifndef CMSG_SPACE
109 #define CMSG_SPACE(size)    (sizeof(struct cmsghdr) + (size))
110 #endif

111 /* POSIX requires the SUN_LEN() macro, but not all implementations define
112    it (yet). Note that this 4.4BSD macro works regardless whether there is
113    a length field or not. */
114 #ifndef SUN_LEN
115 # define    SUN_LEN (su) \
116     (sizeof (*(su)) - sizeof ((su)-&gt;sun_path) + strlen((su)-&gt;sun_path))
117 #endif

118 /* POSIX renames "Unix domain" as "local IPC."
119    Not all systems define AF_LOCAL and PF_LOCAL (yet). */
120 #ifndef AF_LOCAL
121 #define AF_LOCAL    AF_UNIX
122 #endif
123 #ifndef PF_LOCAL
124 #define PF_LOCAL    PF_UNIX
125 #endif

126 /* POSIX requires that an #include of &lt;poll.h&gt; define INFTIM, but many
127    systems still define it in &lt;sys/stropts.h&gt;. We don't want to include
128    all the STREAMS stuff if it's not needed, so we just define INFTIM here.
129    This is the standard value, but there's no guarantee it is -1. */
130 #ifndef INFTIM
131 #define INFTIM          (-1)     /* infinite poll timeout */
132 #ifdef HAVE_POLL_H
133 #define INFTIM_UNPH              /* tell unpxti.h we defined it */
134 #endif
135 #endif

136 /* Following could be derived from SOMAXCONN in &lt;sys/socket.h&gt;, but many
137    kernels still #define it as 5, while actually supporting many more */
138 #define LISTENQ     1024         /* 2nd argument to listen () */

139 /* Miscellaneous constants */
140 #define MAXLINE     4096         /* max text line length */
141 #define BUFFSIZE    8192         /* buffer size for reads and writes */

142 /* Define some port number that can be used for our examples */
143 #define SERV_PORT        9877    /* TCP and UDP */
144 #define SERV_PORT_STR   "9877"   /* TCP and UDP */
145 #define UNIXSTR_PATH    "/tmp/unix.str" /* Unix domain stream */
146 #define UNIXDG_PATH     "/tmp/unix.dg"  /* Unix domain datagram */

147 /* Following shortens all the typecasts of pointer arguments: */
148 #define SA struct sockaddr

149 #define HAVE_STRUCT_SOCKADDR_STORAGE
150 #ifndef HAVE_STRUCT_SOCKADDR_STORAGE
151 /*
152  * RFC 3493: protocol-independent placeholder for socket addresses
153  */
154 #define __SS_MAXSIZE    128
155 #define __SS_ALIGNSIZE  (sizeof(int64_t))
156 #ifdef HAVE_SOCKADDR_SA_LEN
157 #define __SS_PAD1SIZE   (__SS_ALIGNSIZE - sizeof(u_char) - sizeof(sa_family_t))
158 #else
159 #define __SS_PAD1SIZE   (__SS_ALIGNSIZE - sizeof(sa_family_t))
160 #endif
161 #define __SS_PAD2SIZE   (__SS_MAXSIZE - 2*__SS_ALIGNSIZE)

162 struct sockaddr_storage {
163 #ifdef HAVE_SOCKADDR_SA_LEN
164     u_char  ss_len;
165 #endif
166     sa_family_t ss_family;
167     char    __ss_pad1[__SS_PAD1SIZE];
168     int64_t __ss_align;
169     char    __ss_pad2[__SS_PAD2SIZE];
170 };
171 #endif

172 #define FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
173                     /* default file access permissions for new files */
174 #define DIR_MODE    (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
175                     /* default permissions for new directories */

176 typedef void Sigfunc (int);     /* for signal handlers */

177 #define min(a,b)    ((a) &lt; (b) ? (a) : (b))
178 #define max(a,b)    ((a) &gt; (b) ? (a) : (b))

179 #ifndef HAVE_ADDRINFO_STRUCT
180 # include   "../lib/addrinfo.h"
181 #endif

182 #ifndef HAVE_IF_NAMEINDEX_STRUCT
183 struct if_nameindex {
184     unsigned int if_index;      /* 1, 2, ... */
185     char *if_name;              /* null-terminated name: "le0", ... */
186 };
187 #endif

188 #ifndef HAVE_TIMESPEC_STRUCT
189 struct timespec {
190     time_t tv_sec;              /* seconds */
191     long     tv_nsec;           /* and nanoseconds */
192 };
193 #endif
</pre>
<img src ="http://www.cppblog.com/sscchh-2000/aggbug/6836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-09 20:43 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unix网络编程第三版,卷一:套接字联网API学习笔记(1)</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6834.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Tue, 09 May 2006 12:31:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6834.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6834.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6834.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6834.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6834.html</trackback:ping><description><![CDATA[§有关电子资料链接:<a class="" title="" href="http://www.unpbook.com" target="_blank">http://www.unpbook.com/<br /></a>§1.1 介绍<br /><br /><h5 class="docFigureTitle"><a name="ch01fig01"></a>图1.1  网络程序: 客户端和服务器</h5><p class="docText"><img id="129022115118" height="63" alt="graphics/01fig01.gif" src="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/01fig01.gif" width="407" border="0" /><br /><br /><strong><font color="#000000">图 1.2 服务器同时处理多个客户端</font></strong></p><p class="docText"><img id="129022115118" height="272" alt="graphics/01fig02.gif" src="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/01fig02.gif" width="408" border="0" /><br /></p><h5 class="docFigureTitle"><a name="ch01fig03"></a>图 1.3 在同一个以太网使用TCP协议通信的客户端和服务器<img id="129022115118" height="271" alt="graphics/01fig03.gif" src="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/01fig03.gif" width="500" border="0" /><br /><h5 class="docFigureTitle"><a name="ch01fig04"></a>图 1.4 广域网上的客户端与服务器（例如Web浏览器和Web服务器）</h5><p class="docText"><img id="129022115118" height="264" alt="graphics/01fig04.gif" src="mk:@MSITStore:E:\study_magizine\UNIX%20Network%20Programming%20Volume[1].1%20The%20Sockets%20Networking%20API.chm::/FILES/01fig04.gif" width="500" border="0" /></p><p class="docText">§1.2 代码示例和解说</p><p class="docText">1 #include  "unp.h"<br /><br />2 int<br />3 main(int argc, char **argv)<br />4 {<br />5     int     sockfd, n;<br />6     char    recvline[MAXLINE + 1];<br />7     struct sockaddr_in servaddr;<br /><br />8     if (argc != 2)<br />9         err_quit("usage: a.out &lt;IPaddress&gt;");<br /><br />10     if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) &lt; 0)<br />11         err_sys("socket error");<br /><br />12     bzero(&amp;servaddr, sizeof(servaddr));<br />13     servaddr.sin_family = AF_INET;<br />14     servaddr.sin_port = htons(13);  /* daytime server */<br />15     if (inet_pton(AF_INET, argv[1], &amp;servaddr.sin_addr) &lt;= 0)<br />16         err_quit("inet_pton error for %s", argv[1]);<br /><br />17     if (connect(sockfd, (SA *) &amp;servaddr, sizeof(servaddr)) &lt; 0)<br />18         err_sys("connect error");<br /><br />19     while ( (n = read(sockfd, recvline, MAXLINE)) &gt; 0) {<br />20         recvline[n] = 0;        /* null terminate */<br />21         if (fputs(recvline, stdout) == EOF)<br />22             err_sys("fputs error");<br />23     }<br />24     if (n &lt; 0)<br />25         err_sys("read error");<br /><br />26     exit(0);<br />27 }<br />其中unp.h是自定义的头文件，<a class="" title="unp.h文件内容" href="/sscchh-2000/archive/2006/05/09/6836.html" target="_blank">查看源代码</a>。我们编译并执行以上代码，得到以下输出结果：</p><p class="docText"></p><table cellspacing="0" cellpadding="5" rules="none" width="100%" frame="void"><tbody><tr><td class="docTableCell" valign="top"><p class="docText"><tt>solaris %</tt><span class="docEmphStrong"><tt>a.out 206.168.112.96     <span class="docEmphasis">our input</span></tt></span></p></td><td class="docTableCell" valign="top"></td></tr><tr><td class="docTableCell" valign="top"><p class="docText"><tt>Mon May 26 20:58:40 2003          <span class="docEmphasis">the program's output</span></tt></p></td><td class="docTableCell" valign="top"></td></tr></tbody></table></h5>下面简要分析以上27行代码,后续章节中有更详细的讨论.<br /><h4 class="docSection2Title">包含我们自己的头文件</h4><p class="docText"><span class="docEmphasis"><tt>1</tt></span> 该头文件包含了大多数网络程序所需要的多个头文件以及定义了我们将要使用的一些常量(例如 <tt>MAXLINE</tt>).<br /></p><h4 class="docSection2Title"><span class="docEmphasis"><tt><font face="Times New Roman">命令行参数</font></tt></span></h4><h4 class="docSection2Title"><span class="docEmphasis"><tt>2–3</tt></span> 这是含有命令行参数的主函数定义(即main函数).我们以ANSI C标准来书写代码.</h4><h4 class="docSection2Title">创建TCP套接字<a name="ch01lev3sec3"></a></h4><p class="docText"><span class="docEmphasis"><tt>10–11 </tt></span><tt>socket</tt>函数调用创建了一个网络流套接字.(Internet (<tt>AF_INET</tt>) stream (<tt>SOCK_STREAM</tt>) socket), 该函数返回一个整数值,它描述了该套接字,以后的函数通过该整数值来使用这个套接字(例如connect和read等调用). 其中err_开头的函数是我们自定义的函数,详见<a class="" title="sys_开头的自定义函数" href="/sscchh-2000/archive/2006/05/09/6838.html" target="_blank">这里</a>.</p><a name="ch01lev3sec4"></a><h4 class="docSection2Title">确定服务器IP地址和端口号</h4><h4 class="docSection2Title"><span class="docEmphasis"><tt>12–16</tt></span> 我们填充了网络套接字地址结构(一个名为servaddr的结构体sockaddr_in),填充的信息包括服务器IP地址和端口号.我们把整个结构体首先清零,然后设置地址族为AF_INET(IPV6该项为AF_INET6),端口号为13(时间服务器的端口号,是一个大家都知道的端口号).IP地址由命令行参数指定(argv[1]).IP地址和端口号必须按照指定的格式来填充,我们通过调用htons(主机字节流到网络字节流的转换)和inet_pton(点分十进制到32位整数的转换)两个调用来进行转化到所需要的格式.</h4><h4 class="docSection2Title">在调用inet_pton的时候可而能会遇到问题,因为这是IPv6新增的函数,以前的IPv4版本可以调用inet_addr来替代该函数.</h4><p></p><a name="ch01lev3sec5"></a><h4 class="docSection2Title">与服务器建立一个连接</h4><h4 class="docSection2Title"><span class="docEmphasis"><tt>17–18</tt></span> TCP套接字调用connect函数,就与服务器(main函数的第二个参数)建立了一个TCP连接,我们必须指定套接字结构体的第三个参数长度,它总是让编译器通过C的sizeof运算符来计算.</h4><p></p><a name="ch01lev3sec6"></a><h4 class="docSection2Title">读取和显示服务器的回复</h4><h4 class="docSection2Title"><span class="docEmphasis"><tt>19–25</tt></span> 调用read来读取服务器的回复,利用标准I/O来显示该回复信息.此外,在使用TCP的时候我们必须要注意,因为它是一个没有边界的字节流协议.服务器的回复是一个26字节的串:</h4><pre></pre><pre>Mon May 26 20 : 58 : 40 2003\r\n
</pre><pre></pre><p class="docText"><tt>\r</tt> 是回车, <tt>\n</tt> 是换行. <br /><br />终止程序<br /><span class="docEmphasis"><tt>26 </tt></span><tt>exit</tt> 终止程序.Unix在一个进程结束时候总是关闭所有打开的描述符,因此我们的TCP套接字此时关闭了.<br />后续内容将对此有更深入的讨论.</p><img src ="http://www.cppblog.com/sscchh-2000/aggbug/6834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-05-09 20:31 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/05/09/6834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中视图(View)通知对话框(Dialog)的方法</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/04/28/6438.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Fri, 28 Apr 2006 13:47:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/04/28/6438.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6438.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/04/28/6438.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6438.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6438.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在利用				VC				＋				MFC				编程的时候，我们往往能碰到这种情况：在一个模拟程序中（如有些游戏），需要实时显示一些属性的值（文字或者图形），这个时候我们可以重新打开一个对话框（可以是一个模态或者非模态的）来显示这些信息，本文以模态对话框为例，简单实现这个技术。以下代码阴影部分是我利用				ClassWizard				加的，蓝色部分是我手工加的。其余是...&nbsp;&nbsp;<a href='http://www.cppblog.com/sscchh-2000/archive/2006/04/28/6438.html'>阅读全文</a><img src ="http://www.cppblog.com/sscchh-2000/aggbug/6438.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-04-28 21:47 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/04/28/6438.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个读取数据库的问题</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/04/25/6272.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Tue, 25 Apr 2006 13:11:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/04/25/6272.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/6272.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/04/25/6272.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/6272.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/6272.html</trackback:ping><description><![CDATA[
		<p>最近由于要发布交通仿真程序(TSS)的Demo版，以前程序使用的是基于SQL2000数据库的数据源，现在需要改成基于Access数据库，但是在改成Access数据库之后，发现仿真的时候，前台客户端程序可以正常读取Access数据库，而后台服务器进程不能够正确的读取数据库。为什么使用SQL2000数据库的时候没有问题，而使用Access数据库就会出现问题呢？经过调试终于找出了问题：当模拟开始的时候，前台此时正在保存该方案号的信息到数据库中，而此时后台服务器程序也紧接着读取该方案号信息，此时我觉得可能是Access数据库在处理并发的时候出现了问题。以致于服务器进程读取的方案号信息不正确，接下来的其它信息也就不正确了，这就造成了不能正常模拟。〔SQL数据库在处理这种情况时，可能是有一个很好的机制保证了数据的正确性。〕</p>
<img src ="http://www.cppblog.com/sscchh-2000/aggbug/6272.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-04-25 21:11 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/04/25/6272.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中访问Access数据库的方法（不需要用户建立ODBC数据源）</title><link>http://www.cppblog.com/sscchh-2000/archive/2006/04/13/ab.html</link><dc:creator>史传红</dc:creator><author>史传红</author><pubDate>Thu, 13 Apr 2006 05:01:00 GMT</pubDate><guid>http://www.cppblog.com/sscchh-2000/archive/2006/04/13/ab.html</guid><wfw:comment>http://www.cppblog.com/sscchh-2000/comments/5457.html</wfw:comment><comments>http://www.cppblog.com/sscchh-2000/archive/2006/04/13/ab.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/sscchh-2000/comments/commentRss/5457.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sscchh-2000/services/trackbacks/5457.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 由于项目要发布一个单机版，原来用的数据库是大型数据库。需要在单机版中用Access比较方便，另外也不能让用户自己创建数据源，最终的方案就是在程序中直接访问（*.mdb）Access数据库文件，下面简要给出在VC6.0中的访问Access数据库文件的方法：......<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/sscchh-2000/archive/2006/04/13/ab.html'>阅读全文</a><img src ="http://www.cppblog.com/sscchh-2000/aggbug/5457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sscchh-2000/" target="_blank">史传红</a> 2006-04-13 13:01 <a href="http://www.cppblog.com/sscchh-2000/archive/2006/04/13/ab.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>