标签:des style class blog code http
inet_pton和inetntop函数。字母p和n代表presentation和numeric。地址的表达presentation格式通常是ASCIL串,数值(numeric)格式则是存在于套接字地址结构中的二进制值。
inet_pton和inet_ntop函数是比较新的函数,它们能够处理ipv4和ipv6的地址转换。
1. inet_pton
int inet_pton(int af, const char *src, void *dst);将src所指的网络地址字符串(如"192.168.0.1")转换成网络使用的二进制数(unsigned long),存放在dst所指的in_addr结构中。使用基本与inet_aton一致,不同的是多了一个参数af(地址族:AF_INET或AF_INET6,分别对应ipv4和ipv6,对应的地址结构为sockaddr_in和sockaddr_in6)。
使用:
sockaddr_in server_addr; inet_pton(AF_INET, "192.168.0.1", (void *)&server_addr.sin_addr);
2. inet_ntop
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);将src所指的网络二进制数转换成网络地址字符串(如"192.168.0.1"),存放在dst所指字符串和返回值中。相比inet_pton多了个参数cnt,定义缓存区dst的大小,防止溢出。如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC。使用:
sockaddr_in server_addr; char IPdotdec[20]; //存放点分十进制IP地址 inet_pton(AF_INET, "192.168.0.1", (void *)&server_addr.sin_addr); printf(inet_ntop(AF_INET, (void *)&server_addr.sin_addr, IPdotdec, 16)); // 输出"192.168.0.1" printf("%s", IPdotdec); // 输出"192.168.0.1"
//从一个描述符读取n个字节 ssize_t readn(int fd, void* vptr, size_t n) { size_t nleft = n; //记录还剩下多少字节数没读取 ssize_t nread; //记录已经读取的字节数 char* ptr = vptr; //指向要读取数据的指针 while(nleft > 0) //还有数据要读取 { if(nread = read(fd,ptr,nleft) < 0) if(erron == EINTR)//系统被一个捕获的信号中断 nread = 0; //再次读取 else return -1; //返回 else if(nread == 0)//没有出错但是也没有读取到数据 break; //再次读取 nleft -= nread; //计算剩下未读取的字节数 ptr += nread; //移动指针到以读取数据的下一个位置 } return (n-nleft); //返回读取的字节数 } /**************************************************************************************************/ //从一个描述符读文本行,一次一个字节 ssize_t readline(int fd, void* vptr, size_t maxlen)//一个字节一个字节地读取 { ssize_t rc; //每次读取的字符 ssize_t n; //读取的次数也即读取字符串的长度 char c; // char* ptr = vptr; //指向要读取的数据的指针 for(n = 1;n < maxlen; n++) { again: if((rc = read(fd,&c,1)) == 1) { *ptr++ = c; //移动指针 if(c == ‘\n‘) //换行符 break; //跳出循环 else if(rc == 0) //结束 *ptr = 0; //字符串以0结尾 return (n-1); //返回读取的字节数 末尾的0不算 } else { if(erron == EINTR) goto again; //重新读取 return (-1) } } *ptr=0; return n; } /**************************************************************************************************/ //往一个描述符写n个字节 ssize_t writen(ind fd, const void* vptr, size_t n) { size_t nleft = n; //还需要写入的字节数 ssize_t nwritten; //每次写入的字节数 const char* ptr = vptr; //指向要写入的数据的指针 while(nleft > 0) { if((nwritten = write(fd,ptr,nleft)) <= 0) { if(nwritten < 0 && erron == EINTR) nwritten = 0; else return -1; } nleft -= nwritten; //计算还需要写入的字节数 ptr += nwritten; //移动数据指针 } return n; }
值-结果参数
一个套接字函数传递一个套接字地址结构时候,该结构总以引用形式来传递,也就是说传递的指向该结构的一个指针,该结构的长度也作为一个参数来传递,不过其传递方式取决于该结构的传递方向:是从进程到内核,还是从内核到进程.如下图所示:
fork和exec函数:
fork最困难的部分是它调用一次却返回两次。在调用进程(称为父进程),它返回一次,返回值是新派生进程(称为子进程)的进程ID,在子进程中它还返回一次,返回0。可通过返回值来判断当前进程是子进程还是父进程。
fork在子进程返回0而不是父进程ID,原因是:子进程只有一个父进程,他总可以调用getppid来得到;而父进程有许多子进程,他没有办法得到各子进程ID。如果父进程想跟踪所有子进程ID,他必须记住fork的返回值。
getsockname与getpeername
是返回套接口关联的本地协议地址和远程协议地址。
int getsockname(int sockfd, struct sockaddr * localaddr, socken_t * addrlen);
int getpeername(int sockfd, struct sockaddr * peeraddr, socken_t * addrlen);
返回0表示成功,返回1表示出错
参数sockfd表示你要获取的套接口的描述字。
localaddr返回本地协议地址描述结构, peeraddr返回远程协议地址描述结构,addrlen分别是上述2个结构的长度。
注意,2个函数的最后一个参数是值-结果参数。
需要这两个函数的理由如下:
在一个没有调用bind的TCP客户上,connect成功返回后,getsockname用于返回由内核赋予该连接的本地IP地址和本地端口号。
在以端口号为0调用bind(告知内核去选择本地临时端口号)后,getsockname用于返回由内核赋予的本地端口号。
在一个以通配IP地址调用bind的TCP服务器上,与某个客户的连接一旦建立(accept成功返回),getsockname就可以用于返回由内核赋予该连接的本地IP地址。在这样的调用中,套接字描述符参数必须是已连接套接字的描述符,而不是监听套接字的描述符。
当一个服务器是由调用过accept的某个进程通过调用exec执行程序时,它能够获取客户身份的唯一途径便是调用getpeername。
显然,最后一个例子中的Telnet服务器必须在启动之后获取connfd的值。获取该值有两个常用方法:
调用exec的进程可以把这个描述符格式化成一个字符串,再把它作为一个命令行参数传递给新程序。
约定在调用exec之前,总是把某个特定描述符置为所接受的已连接套接字的描述符。
inetd采用的是第二种方法,它总是把描述符0、1、2置为所接受的已连接套接字的描述符(即将已连接套接字描述符dup到描述符0、1、2,然后close原连接套接字)。
服务器的代码:
#include "unp.h" int main(int argc, char ** argv) { int listenfd,connfd; struct sockaddr_in servaddr; pid_t pid; char temp[20]; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(10010); Bind(listenfd, (SA *)&servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); for( ; ; ) { struct sockaddr_in local; connfd = Accept(listenfd, (SA *)NULL, NULL); if((pid = fork()) == 0) { Close(listenfd);struct sockaddr_in serv, guest; char serv_ip[20]; char guest_ip[20]; socklen_t serv_len = sizeof(serv); socklen_t guest_len = sizeof(guest); getsockname(connfd, (struct sockaddr *)&serv, &serv_len); getpeername(connfd, (struct sockaddr *)&guest, &guest_len); Inet_ntop(AF_INET, &serv.sin_addr, serv_ip, sizeof(serv_ip)); Inet_ntop(AF_INET, &guest.sin_addr, guest_ip, sizeof(guest_ip)); printf("host %s:%d guest %s:%dn", serv_ip, ntohs(serv.sin_port), guest_ip, ntohs(guest.sin_port)); char buf[] = "hello world"; Write(connfd, buf, strlen(buf)); Close(connfd); exit(0); } Close(connfd); } }
客户端的代码:
#include "unp.h" #define DEST_IP "127.0.0.1" int main(int argc, char ** argv) { int sockfd, n; char buf[100]; char serv_ip[20], guest_ip[20]; struct sockaddr_in servaddr; sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(struct sockaddr_in)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(10010); Inet_pton(AF_INET, DEST_IP, &servaddr.sin_addr); Connect(sockfd, (SA *)&servaddr, sizeof(servaddr)); struct sockaddr_in serv, guest; socklen_t serv_len = sizeof(serv); socklen_t guest_len = sizeof(guest); getsockname(sockfd, (SA *)&guest, &guest_len); getpeername(sockfd, (SA *)&serv, &serv_len); Inet_ntop(AF_INET, &guest.sin_addr, guest_ip, sizeof(guest_ip)); Inet_ntop(AF_INET, &serv.sin_addr, serv_ip, sizeof(serv_ip)); printf("host %s:%d, guest %s:%dn", serv_ip, ntohs(serv.sin_port), guest_ip, ntohs(guest.sin_port)); n = Read(sockfd, buf, 100); buf[n] = ‘?‘; printf("%sn", buf); Close(sockfd); exit(0); }
TCP
对于服务器来说,在bind以后就可以调用getsockname来获取本地地址和端口,虽然这没有什么太多的意义。getpeername只有在链接建立以后才调用,否则不能正确获得对方地址和端口,所以他的参数描述字一般是链接描述字而非监听套接口描述字。
对于客户端来说,在调用socket时候内核还不会分配IP和端口,此时调用getsockname不会获得正确的端口和地址(当然链接没建立更不可能调用getpeername),当然如果调用了bind 以后可以使用getsockname。想要正确的到对方地址(一般客户端不需要这个功能),则必须在链接建立以后,同样链接建立以后,此时客户端地址和端口就已经被指定,此时是调用getsockname的时机。
http://blog.chinaunix.net/zt/1016/unixjian_1016285.shtml
http://blog.csdn.net/yirancpp/article/details/8446879
http://tech.ddvip.com/2013-07/1374769636199661.html
标签:des style class blog code http
原文地址:http://www.cnblogs.com/youxin/p/3804843.html