unix network programming(3rd)Vol.1 [第1章]《读书笔记系列》
文章最开头介绍了
-
获取时间的C/S 模型的代码, 还用了实现了IPV6的版本
-
unix 介绍了errno值,以及在多进程/多线程中的问题
多线程中不用全局errno,而是用返回值 处理error 详细见第26章
//可以这么写
int n;
if( (n=pthread_mutex_lock(&ndone_mutex)) !=0 )
errno=n,err_sys("ptherad_mutex_lock error");// 逗号分割,不用{} 花括号
//当然我们也可以封装下
void warpper_Pthread_mutex_lock(pthread_mutex *mptr)
{
int n;
if( (n=pthread_mutex_lock(mptr) ) == 0 )
return;
errno = n;
err_sys("ptherad_mutex_lock error");
}
-
简单介绍了,buffer溢出老问题,基本上也都是c99/c11/c++11替换老版本
windows 是 _s系列 比如strcpy_s, memcpy_s, sprintf_s
当然wide strings版本也有封装 wsprinf_s,wmemcpy_s
linux 的wide strings头文件是(wchar.h) printf() -> puts() Write string to stdout
gets() -> fgets()
sprintf() -> snprintf()
strcat()-> strncat()->strlcat()//最好用strlcat
strcpy()-> strncpy()->strlcpy()//最好用strlcpy等等
《Strlcpy和strlcat——一致的、安全的字符串拷贝和串接函数 》详细介绍了为什么 英文原版
中文版
size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
简单概括:
strcat、strcpy 容易溢出,
strncat、strncpy() 最后一位需要手动 置0, (strncpy 当目标缓冲区远远大于源字符串的长度时,剩下的空闲数据都需要置0,导致性能降低) 还要strnlen去计算实际长度
以上函数的滥用的太多
所以最好使用strlcpy(),由于是openBSD,gnulibc并没有,所以有可能要自己实现。(或者自己从bsd 中弄下来)
ftp://ftp.openbsd.org/pub/OpenBSD/5.7/src.tar.gz
http://www.opensource.apple.com/ 中可以找到任意OSX版本的代码 最新的OS X 是 10.10.2
这里多插一句,顺便看了下http://www.opensource.apple.com/source/tcp_wrappers/tcp_wrappers-20/tcp_wrappers/socket.c.diff
里面修改的也就是 同时兼容 IPV4/IPV6。
代码格式命名还是和UNP 这本书中一模一样,
我也不做评论了,大家自己看吧
strcpy
strcat
strncpy
strncat
就不一一列举了,都在目录 中
旧版本 http://www.opensource.apple.com/source/Libc/Libc-320/string/FreeBSD/
strlcpy.3
strlcpy.c
strlcpy
// man 手册中 A simple implementation of strncpy() might be:
char *strncpy(char *dest, const char *src, size_t n)
{
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++)
dest[i] = src[i];
for ( ; i < n; i++)
dest[i] = '\0';
return dest;
}
//=========== OpenBSD 5.7 版本的strlcpy OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t strlcpy(char *dst, const char *src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}
//===========MACOS Libc-1044.10.1版本的strlcpy
#include <strings.h>
size_t strlcpy(char * restrict dst, const char * restrict src, size_t maxlen) {
const size_t srclen = strlen(src);
if (srclen < maxlen) {
memcpy(dst, src, srclen+1);
} else if (maxlen != 0) {
memcpy(dst, src, maxlen-1);
dst[maxlen-1] = '\0';
}
return srclen;
}
strlcat
/*
* Copyright (c) 2011 Apple, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <strings.h>
size_t
strlcat(char * restrict dst, const char * restrict src, size_t maxlen) {
const size_t srclen = strlen(src);
const size_t dstlen = strnlen(dst, maxlen);
if (dstlen == maxlen) return maxlen+srclen;
if (srclen < maxlen-dstlen) {
memcpy(dst+dstlen, src, srclen+1);
} else {
memcpy(dst+dstlen, src, maxlen-dstlen-1);
dst[maxlen-1] = '\0';
}
return dstlen + srclen;
}
习题
netstat -ni -i显示网络接口信息,n 输出数值信息
netstat -nr -r显示路由表,-n输出数值地址
ifconfig eth0 可以看到设备MTU 1500(默认)
errno 可以在 include <errno.h> 中找到对因number的意义,man page也可以找到
getaddrinfo()可以取得IPv4/IPV6 地址,从而写出IPv4/IPV6通用的 代码。
MAC OS X inet_ntop 中还是用了static变量 ,多线程 还是会出现问题(http://www.opensource.apple.com/source/Libc/Libc-1044.1.2/net/inet_pton.c)
IP地址 字符串 与 网络字节序二进制 互相转换
n numberic 1100 0000 1010 1000 0000 0001 0000 0001
a ASC II "192.168.1.1"
inet_pton
inet_ntop
(p 代表 presentation n 代表numberic 支持IPV4IPv6,都是封装了inet_aton/inet_ntoa/ inet_addr 这些函数,加了些判断处理)
int inet_pton(int af, const char *src, void *dst);
inet_pton - convert IPv4 and IPv6 addresses from text to binary form string,转换 字符串地址 到 binary地址
struct sockaddr_in servaddr_IPV4;
struct sockaddr_in6 servaddr_IPV6;
inet_pton(AF_INET, "192.168.1.200", &servaddr_IPV4.sin_addr);
inet_pton(AF_INET6, argv[1], &servaddr_IPV6.sin6_addr); //argv[1] 是ipv6 地址
推荐用新的inet_pton、inet_ntop 同时支持IPV4/IPV6
看到了sin_addr 结构之后可以用snprintf()自己实现(其实以前不知道这个函数,自己实现过很多遍)
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
既然知道是uint32_t 那么unsigned int 是 32bits, 0000 0000 0000 0000 每8bit代表一个段,0~255
要注意little-end, big-end 问题, 因为要转换到网络地址。
本地 x86/x86_x64 都是little-end, IBM POWER PC是big-end
网络上是big-end。
具体参见《深入理解计算机系统》最新是3rd,本书后面也有详细介绍。
On the i386 the host byte order is Least Significant Byte first,whereas the network byte order, as used on the Internet, is Most Significant Byte first.
htonl, htons, ntohl, ntohs - convert values between host and network byte order
htonl 主机字节序转换成网络字节序
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); //host convert to network long
uint16_t htons(uint16_t hostshort); //host convert to network short
uint32_t ntohl(uint32_t netlong); // network convert to host long
uint16_t ntohs(uint16_t netshort); // network convert to host short
16bit 用于 端口号
32bit 用于 IP地址(仅仅是IPV4)