1. We must be careful when using TCP because it is a byte-stream protocol with no record boundaries. The server's reply is normally a string. With a byte-stream protocol, the bytes of the string can be returned in numerous ways: a single TCP segment containing all bytes of data, in many TCP segments each containing 1 byte of data, or any other combination. We cannot assume that the server's reply will be returned by a single read. Therefore, when reading from a TCP socket, we always need to code the read in a loop and terminate the loop when either read returns 0 (i.e., the other end closed the connection) or a value less than 0 (an error).
2. When an error occurs in a Unix function, the global variable errno is set to a positive value indicating the type of error and the function normally returns -1.
The value of errno is set by a function only if an error occurs. Its value is undefined if the function does not return an error. All of the positive error values are constants with all-uppercase names beginning with "E," and are normally defined in the header. No error has a value of 0.
Storing errno in a global variable does not work with multiple threads that share all global variables.
非线程函数通常返回 -1 表示出错,然后用 errno 的值来表示出错的原因;而线程函数却是用不同的返回值来表示各种不同的错误的原因。
3. We specify the IP address as INADDR_ANY, which allows the server to accept a client connection on any interface, in case the server host has multiple interfaces.
这里的意思是对于多网卡的服务器,指定IP地址为INADDR_ANY可以接受来自本主机的任何一块网卡的信息。
4. If you're not already in the habit of using snprintf instead of the older sprintf, now's the time to learn. Calls to sprintf cannot check for overflow of the destination buffer. snprintf, on the other hand, requires that the second argument be the size of the destination buffer, and this buffer will not overflow.
It is remarkable how many network break-ins have occurred by a hacker sending data to cause a server's call to sprintf to overflow its buffer. Other functions that we should be careful with are gets, strcat, and strcpy, normally calling fgets, strncat, and strncpy instead. Even better are the more recently available functions strlcat and strlcpy, which ensure the result is a properly terminated string. Additional tips on writing secure network programs are found in Chapter 23 of [Garfinkel, Schwartz, and Spafford 2003].
5. being aware of some properties of the datalink, such as the 1500-byte Ethernet maximum transfer unit (MTU)
6. it is possible for an application to bypass the transport layer and use IPv4 or IPv6 directly. This is called a raw socket.
we will see that we can even bypass the IP layer completely to read and write our own datalink-layer frames.
7. The sockets API originated with the 4.2BSD system, released in 1983.
A few changes to the sockets API also took place in 1990 with the 4.3BSD Reno release, when the OSI protocols went into the BSD kernel.
8. Some Unix versions have Berkeley-derived networking code, while the networking code in other SVR4 systems has been independently derived. We also note that Linux, a popular, freely available implementation of Unix, does not fit into the Berkeley-derived classification: Its networking code and sockets API were developed from scratch.
9. netstat -i provides information on the interfaces. We also specify the -n flag to print numeric addresses, instead of trying to find names for the networks. This shows us the interfaces and their names.
netstat -r shows the routing table, which is another way to determine the interfaces. We normally specify the -n flag to print numeric addresses. This also shows the IP address of the default router.
Given the interface names, we execute ifconfig to obtain the details for each interface: ifconfig eth0
This shows the IP address, subnet mask, and broadcast address. The MULTICAST flag is often an indication that the host supports multicasting. Some implementations provide a -a flag (ifconfig -a), which prints information on all configured interfaces.
One way to find the IP address of many hosts on the local network is to ping the broadcast address.
10. During the mid to late 1990s, the trend began toward 64-bit architectures and 64-bit software. One reason is for larger addressing within a process (i.e., 64-bit pointers). The common programming model for existing 32-bit Unix systems is called the ILP32 model, denoting that integers (I), long integers (L), and pointers (P) occupy 32 bits. The model for 64-bit Unix systems is called the LP64 model, meaning only long integers (L) and pointers (P) require 64 bits.
11. From a programming perspective, the LP64 model means we cannot assume that a pointer can be stored in an integer. We must also consider the effect of the LP64 model on existing APIs.
12. ANSI C invented the size_t datatype, on a 32-bit system, size_t is a 32-bit value, but on a 64-bit system, it must be a 64-bit value, to take advantage of the larger addressing model. This means a 64-bit system will probably contain a typedef of size_t to be an unsigned long. The networking API problem is that some drafts of POSIX.1g specified that function arguments containing the size of a socket address structures have the size_t datatype (e.g., the third argument to bind and connect). The solution is to use datatypes designed specifically to handle these scenarios. The sockets API uses the socklen_t datatype for lengths of socket address structures.The reason for not changing these values from 32 bits to 64 bits is to make it easier to provide binary compatibility on the new 64-bit systems for applications compiled under 32-bit systems.
阅读(1168) | 评论(0) | 转发(0) |