Chinaunix首页 | 论坛 | 博客
  • 博客访问: 314855
  • 博文数量: 79
  • 博客积分: 1480
  • 博客等级: 上尉
  • 技术积分: 848
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-11 15:29
文章分类

全部博文(79)

文章存档

2012年(1)

2011年(5)

2010年(19)

2009年(54)

我的朋友

分类: C/C++

2010-08-23 15:22:37

1、Socket Descriptor
(1)socket是一个抽象的通信endpoint,许多对fd有效的函数比如read write对soket descriptor同样有效
(2)socket()创建一个socket

#include <sys/socket.h>

int socket(int domain, int type, int protocol);
            Returns: file(socket) descriptor if OK, -1 on error

domain:   
 Domain Description
   
 AF_INET IPv4 Internet domain 
 AF_INET6 Ipv6 Internet domain
 AF_UNIX UNIX domain 
 AF_UNSPEC unspecified 
type:
 TypeDescription 
  
 SOCK_DGRAMfixed-length, connectionless, unreliable message 
 SOCK_RAWdatagram interface to IP (optional in POSIX.1)
 SOCK_SEQPACKETfixed-length, sequenced, reliable, connection-oritentd messages 
 SOCK_STREAMsequenced, reliable, bidirectional, connection-oritentd byte streams 

protocol:通常为0
         AF_INET,SOCK_STREAM默认协议为TCP
         AF_INET,SOCK_DGRAM默认协议为UDP
(3)作用于FD的函数在SOCKET上的表现
 Functon Behavior with socket 

 
close  deallocates the socket 
dup, dup2 duplicates  the file descriptor as normal
fchdir 失败,errno==ENOTDIR 
fchmod unspecified 
fchown implementation defined 
fcntl 支持一些命令: F_DUPFD, F_GETFD, F_GETFL, F_GETOWN, F_SETFD, F_SETFL 和 F_SETOWN 
fdatasync, fsync  implementation defined 
fstat支持一些struct stat成员,但是怎么支持留给了配置
ftruncate unspecified 
getmsg, getpmsg 如果配置成STREAMS,则支持 
ioctl 根据底层驱动,一些命令支持 
lseek implemetation defined(一般失败,errno == ESPIPE) 
mmap unspecified 
poll 正常工作 
putmsg, putpmsg  如果配置成STREAMS,则支持
read, readv 等同于不带任何flag的recv 
select 正常工作 
write, writev 等同于不带任何flag的send 
(4)disable I/O on a socket

#include <sys/socket.h>

int shutdown(int sockfd, int how);
               Returns: 0 if OK, -1 on error

how:
    SHUT_RD:关闭read
    SHUT_WR:关闭write
    SHUT_RDWR:关闭读写
注:close只有在最后一个活动reference关闭,才会deallocate网络endpoint;而shutdown没有这个限制,立即deactive,同时,shutdown可以只关闭读或者写
2、Addressing
(1)big-endian and little-endian
表达数字:0x11223344
 低地址  0x       高地址 
 big-endian  11 22  33  44   
 little-endian  44  33  22  11   
MSB(Most Significant Byte):最高有效位0x11,跟byte order没关系
LSB(Least Significant Byte):最低有效位0x44,跟byte order没关系
 Operating system Processor architecture  Byte order 
    
 FreeBSD 5.2.1 Intel Pentium  little-endian 
 Linux 2.4.22 Intel Pentium  little-endian 
 Mac OS X 10.3 PowerPC  big-endian 
 Solaris 9 Sun SPARC  big-endian 
(2)转换函数

#include <appa/inet.h>
uint32_t htonl(uint32_t hostint32);
          Returns: 32-bit integer in network byte order

uint16_t htons(uint16_t hostint 16);
          Returns: 16-bit integer in network byte order

uint32_t ntohl(uint32_t netint32);
          Returns: 32-bit integer in host byte order

uint16_t ntohs(uint16_t netint 16);
          Returns: 16-bit integer in host byte order

(3)Address Formats(linux)

struct sockaddr {
    sa_family_t sa_family; // address family

    char sa_data[14]; // variable-length address

};

#include <netinet/in.h>

struct in_addr{
   in_addr_t s_addr; // Ipv4 address

};

struct sockaddr_in {
   sa_family_t sin_family;// address family

   in_port_t sin_port; // port number

   struct in_addr sin_addr;// Ipv4 address

   unsigned char sin_zero[8]; // filler

};

(4)ip地址(a.b.c.d)和二进制地址转换
只针对IPV4

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int inet_aton(const char *cp, struct in_addr *inp);
//转换网络主机地址cp为二进制数值,并存储在struct in_addr结构中,即第二个参数*inp,函数返回非0表示cp主机有地有效,返回0表示主机地址无效


in_addr_t inet_addr(const char *cp);
//转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char *cp无效,函数返回-1(INADDR_NONE),这个函数在处理地址为255.255.255.255时也返回- 1,255.255.255.255是一个有效的地址,不过inet_addr无法处理


char *inet_ntoa(struct in_addr in);

//转换网络字节排序的地址为标准的ASCII以点分开的地址,该函数返回指向点分开的字符串地址指针。该字符串的空间为静态分配,这意味着在第二次调用该函数时,上一次调用会被重写(覆盖),所以如果需要保存该串最后复制出来自己管理

针对IPV4和IPV6

#include <arpa/inet.h>
const char *inet_ntop(int domain, const void *restrict addr, char *restrict str, socklen_t size);
          Returns: pointer to address string on success, NULL on error

int inet_pton(int domain, const char *restrict str, void *restrict addr);
          Returns: 1 on success, 0 if the format is invalid, or -1 on error

domain: AF_INET or AF_INET6
size:存储str的buffer大小,一般设置为INET_ADDRSTRLEN或者INET6_ADDRSTRLEN
inet_pton的addr: 必须大到容纳IPV4或者IPV6的地址
(5)获取host database file

#include <netdb.h>
struct hostent *gethostent(void);
         Returns: pointer if OK, NULL on error

void sethostent(int stayopen);

void endhostent(void);

gethostent返回文件的下一个entry; sethostent打开文件,如果已经打开了,回绕(rewind)它; endhostent关闭文件。

struct hostent {
   char *h_name; // name of host

   char **h_aliases; // pointer to alternate host name array

   int h_addrtype; // address type

   int h_length; // length in bytes of address

   char **h_addr_list; // pointer to array of network address

   .
   .
   .
};

(6)获取主机名字
旧函数

#include <unistd.h>
int gethostname(char *name, size_t len);
参数说明:
这个函数需要两个参数:
接收缓冲区name,其长度必须为len字节或是更长
接收缓冲区name的最大长度
返回值:
如果函数成功,则返回0。如果发生错误则返回-1。错误号存放在外部变量errno中。

int getdomainname(char *name,size_t len);
参数说明:
这个函数的用法也gethostname相同。

struct hostent *gethostbyaddr(const char *name)
传入值是IP地址(注意,这里不是简单的字符串,需要先将字符串形式的IP地址由inet_aton转化一下),然后经过函数处理,将结果由返回值传出。返回值是一个hostent结构.因为有了hosten这个传出的结构,我们可以在这个结构里面找到我们想需要的信息。

#include <netdb.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name);
这个函数的传入值是域名或者主机名,例如"","wpc"等等。
传出值,是一个hostent的结构。如果函数调用失败,将返回NULL。

取代函数

#include <netdb.h>
struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent *getnetent(void);
           All return: pointer if OK, NULL on error

void setnetent(int stayopen);
void endnetent(void);

struct netent{
   char *name; // network name
   char **n_aliases; // alternate network name array pointer
   int n_addrtype; // address type
   uint32_t network number;
   .
   .
   .
};

(7)map between protocol names and numbers

#include <netdb.h>
struct protoent *getprotobyname(const char *name);
struct protoent *getprotobynumber(int proto);
struct protoent(void);
        All return: pointer if OK, NULL on error

void setprotoent(int stayopen);
void endprotoent(void);

stuct protoent:

struct protoent{
   char *p_name; //protocol name
   char **p_aliases; // pointer to alternate protocol name array
   int p_proto//protocol number
   .
   .
   .
}
;

(8)map between server name and port number

#include <netdb.h>
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
struct servent *getservent(void);
        All return: pointer if OK, NULL on error

void setservent(int stayopen);
void endservent(void);


struct servent {
    char *s_name; //server name
    char **s_aliases; // pointer to alternate service name array
    int s_port; // port number
    char *s_proto; // name of protocol
    .
    .
    .
};

(9)map “主机名or服务名” to “地址”

#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *restrict host, const char *restrict service, const struct addrinfo *restrict hint, struct addrinfo **restrict res);
     Returns: 0 if OK, nonzero error code on error

void freeaddrinfo(struct addrinfo *ai);


struct addrinfo{
   int ai_flags; // customize behavior,P556
   int ai_family; // address family
   int ai_socktype; // socket type
   int ai_protocol; // protocol
   socklen_t ai_addrlen; // length in bytes of address
   struct sockaddr *ai_addr; // address
   char *ai_canonname; // canonical name of host
   struct addrinfo *ai_next; // next in list
   .
   .
   .
};

getaddrinfo返回的是一个struct addrinfo的链表
如果返回错误,必须用gai_strerror转换error code到error message

#include <netdb.h>
const char *gai_strerror(int error);
          Returns: a pointer to a string describing the error

(9)map "地址" to "主机名+服务名"

#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *restrict addr, socklen_t alen, char *restrict host, socklen_t host_len, char *restrict service, socklen_t servlen, unsigned int flags);         P557
       Returns: 0 if OK, nonzero on error

(10)Associate Addresses with Sockets

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
          Returns: 0 if OK, -1 on error

注:1、地址端口号不能小于1024,除非是superuser才能这么设定;
   2、只能是1个socket endpoint绑定到给定地址,虽然有一些协议允许duplicate bindings
   3、如果地址设置为INADDR_ANNY,则socket endpoint绑定到系统上所有的network interface上,这样可以接受从系统上所有网卡传送过来的包

#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
       Returns: 0 if OK, -1 on error

注:1、查看绑定到socket的地址
   2、alenp:指向一个整数,包含sockaddr buffer的大小,一旦函数返回,就被设置返回的地址大小; 如果buffer太小,返回的地址会被truncated

#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp)

注:1、获取peer地址,其它同getsockname
阅读(1207) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~