unix network programming(3rd)Vol.1 [第1章]《读书笔记系列》

时间:2021-06-24 10:23:38

文章最开头介绍了

  • 获取时间的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 这本书中一模一样,

我也不做评论了,大家自己看吧

最新版本代码

strlcpy.c

strlcat

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)