linux网络编程笔记 日期:2009-03-26 ------------------------------ 套接字类型: 1、 SOCK_STREAM (面向连接,TCP/IP) 2、 SOCK_DGRAM (无连接,UDP) ------------------------------ 网络数据包结构体 struct sockaddr { unsigned short sa_family; /* 地址家族, AF_xxx */ char sa_data[14]; /*14字节协议地址*/ }; struct sockaddr_in { short int sin_family; /* 通信类型 */ unsigned short int sin_port; /* 端口 */ struct in_addr sin_addr; /* Internet 地址 */ unsigned char sin_zero[8]; /* 与sockaddr结构的长度相同*/ }; struct in_addr { unsigned long s_addr; }; struct hostent { char *h_name; /* official name of host * / char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ } ------------------------------ 一些简单的缩写表示 h => host 2 => to n => network s => short(从本机字节顺序转 换为网络字节顺序。) htons() => h-to-n-s => Host to Network Short htonl() => h-to-n-l => Host to Network Long ntohs() => n-to-h-s => Network to Host Short ntohl() => n-to-h-l => Network to Host Long ------------------------------ 网络IP地址及处理 一、将IP地址从点数格式转换成无符号长整型。 struct sockaddr_in ina; ina.sin_addr.s_addr = inet_addr("132.241.5.10"); /*inet_addr发生错误时,返回-1*/ 二、 in_addr 结构体输出成点数格式 inet_ntoa()("ntoa"的含义是"network to ascii"), printf("%s",inet_ntoa(ina.sin_addr)); 使用inet_ntoa需要注意的是: 1、inet_ntoa()将结构体in-addr作为一 个参数,不是长整形。 2、它返回的是一个指向一个字符串的指针。它是一个由inet_ntoa()控制的静态的固定的指针,所以每次调用inet_ntoa(),它就将覆盖上次调用时所得的IP地址。 char *a1, *a2; a1 = inet_ntoa(ina1.sin_addr); /* 这是198.92.129.1 */ a2 = inet_ntoa(ina2.sin_addr); /* 这是132.241.5.10 */ printf("address 1: %s\n",a1); printf("address 2: %s\n",a2); 输出如下: address 1: 132.241.5.10 address 2: 132.241.5.10 ------------------------------ socket()函数 #include <sys/types.h> #include <sys/socket.h> /** *返回socket描述符。 *return:错误发生时返回-1. */ int socket(int domain, int type, int protocol); domain: 应该设置成 "AF_INET",就象上面的数据结构struct sockaddr_in 中一样。 type: SOCK_STREAM 或者 SOCK_DGRAM protocol: 一般为0 ------------------------------ bind()函数 #include <sys/types.h> #include <sys/socket.h> /** *客户端绑定的端口号,端口号为0时表示随机选择一个可用的端口号。 *return: 发生错误时返回-1 */ int bind(int sockfd, struct sockaddr *my_addr, int addrlen); sockfd: 是调用 socket 返回的文件描述符。 my_addr: 是指向数据结构 struct sockaddr 的指针,它保存你的地址(即端口和 IP 地址) 信息。 addrlen: 设置为 sizeof(struct sockaddr)。 my_addr.sin_port = htons(0); /* 随机选择一个没有使用的端口 */ my_addr.sin_addr.s_addr = htonl(INADDR_ANY);/* 使用自己的IP地址 */ ------------------------------ connect()函数 #include <sys/types.h> #include <sys/socket.h> /** * *return: 发生错误时返回-1 */ int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); sockfd: 是系统调用 socket() 返回的套接字文件描述符。 serv_addr: 是 保存着目的地端口和 IP 地址的数据结构 struct sockaddr。 addrlen: 设置 为 sizeof(struct sockaddr)。 ------------------------------ listen()函数 /** *return: 发生错误时返回-1 */ int listen(int sockfd, int backlog); sockfd: 是调用 socket() 返回的套接字文件描述符。 backlog: 是在进入队列中允许的连接数目。进入的连接是在队列中一直等待,直到你接受( accept() ) 连接。它们的数目限制于队列的允许。大多数系统的允许数目是20,你也可以设置为5到10。 ------------------------------ accept()函数 #include <sys/socket.h> int accept(int sockfd, void *addr, int *addrlen); sockfd 是调用 socket() 返回的套接字文件描述符。 addr 是个指向局部的数据结构 sockaddr_in 的指针。这是要求接入的信息所要去的地 方(你可以测定那个地址在那个端口呼叫你)。在它的地址传递给 accept 之 前。 addrlen 是个局部的整形变量,设置为 sizeof(struct sockaddr_in)。 ------------------------------ send() and recv()函数 这两个函数用于流式套接字或者数据报套接字的通讯。 int send(int sockfd, const void *msg, int len, int flags); sockfd: 是你想发送数据的套接字描述符(或者是调用 socket() 或者是 accept() 返回的。) msg: 是指向你想发送的数据的指针。 len: 是数据的长度。 把 flags 设置为 0 就可以了。 send() 返回实际发送的数据的字节数--它可能小于你要求发送的数目. 注意,有时候你告诉它要发送一堆数据可是它不能处理成功。它只是 发送它可能发送的数据,然后希望你能够发送其它的数据。 记住,如果 send() 返回的数据和 len 不匹配,你就应该发送其它的数据。但是这里也 有个好消息:如果你要发送的包很小(小于大约 1K),它可能处理让数据一 次发送完。最后要说得就是,它在错误的时候返回-1,并设置 errno。 recv() 函数 int recv(int sockfd, void *buf, int len, unsigned int flags); sockfd 是要读的套接字描述符。 buf 是要读的信息的缓冲。 len 是缓 冲的最大长度。 flags 可以设置为0。(请参考recv() 的 man page。) recv() 返回实际读入缓冲的数据的字节数。或者在错误的时候返回-1, 同时设置 errno。 ------------------------------ sendto() 和 recvfrom()函数 int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); struct sockaddr 的指针,它包含了目的地的 IP 地址和端口信息。 tolen 可以简单地设置为 sizeof(struct sockaddr)。 int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); from 是一个指向局部数据结构 struct sockaddr 的指针,它的内容是源机器的 IP 地址和端口信息。 fromlen 是个 int 型的局部指针,它的初始值为 sizeof(struct sockaddr)。 记住,如果你用 connect() 连接一个数据报套接字,你可以简单的调 用 send() 和 recv() 来满足你的要求。这个时候依然是数据报套接字,依 然使用 UDP,系统套接字接口会为你自动加上了目标和源的信息。 ------------------------------ close()和shutdown()函数 int close(int sockfd); int shutdown(int sockfd, int how); sockfd 是你想要关闭的套接字文件描述复。 how 的值是下面的其中之 一: 0 – 不允许接受 1 – 不允许发送 2 – 不允许发送和接受(和 close() 一样) shutdown() 成功时返回 0,失败时返回 -1 ------------------------------ getpeername()函数 #include <sys/socket.h> int getpeername(int sockfd, struct sockaddr *addr, int *addrlen); sockaddr_in 的指针,它保存着连接的另一边的 信息。 addrlen 是一个 int 型的指针,它初始化为 sizeof(struct sockaddr)。 函数在错误的时候返回 -1 一旦你获得它们的地址,你可以使用 inet_ntoa() 或者 gethostbyaddr() 来打印或者获得更多的信息。 ------------------------------ gethostname()函数 #include <unistd.h> int gethostname(char *hostname, size_t size); 获取程序所运行的机器的主机名字 hostname 是一个字符数组指针,它将在函数返回时保存 主机名。 size是hostname 数组的字节长度。 ------------------------------ gethostbyname()函数 #include <netdb.h> struct hostent *gethostbyname(const char *name); 返回一个指向 struct hostent 的指针。 struct hostent { char *h_name; /* official name of host * / char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ } h_name – 地址的正式名称。 h_aliases – 空字节-地址的预备名称的指针。 h_addrtype –地址类型; 通常是AF_INET。 h_length – 地址的比特长度。 h_addr_list – 零字节-主机网络地址指针。网络字节顺序。 h_addr - h_addr_list中的第一地址。