《2022年2022年计算机网络课程设计实验报告 2.pdf》由会员分享,可在线阅读,更多相关《2022年2022年计算机网络课程设计实验报告 2.pdf(35页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、计算机网络课程设计实验报告名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 35 页 - - - - - - - - - 一、 实验内容和要求1、实验一 数据包的捕获与分析Wireshark是一种开源的网络数据包的捕获和分析软件,本实验通过Wireshark软件的安装使用,监控局域网的状态,捕获在局域网中传输的数据包,并结合在计算机网络课程中学习到的理论知识,对常用网络协议的数据包做出分析,加深网络课程知识的理解和掌握。具体内容及要求如下:Wireshark软件的安装;Wi
2、reshark软件的启动,并设置网卡的状态为混杂状态,使得Wireshark可以监控局域网的状态;启动数据包的捕获,跟踪PC之间的报文,并存入文件以备重新查;设置过滤器过滤网络报文以检测特定数据流;对常用协议的数据包的报文格式进行分析,利用协议分析软件的统计工具显示网络报文的各种统计信息。2、实验二网络层实验Ping 程序的设计与实现实验目的本实验目的是使学生掌握网络层协议的原理及实现方法。实验设计内容本实验为ICMP实验。 实验内容: Ping 命令实现的扩充,在给定的Ping 程序的基础上做如下功能扩充:-h 显示帮助信息-b 允许 ping 一个广播地址,只用于IPv4 -t 设置 tt
3、l值,只用于IPv4 -q 安静模式。不显示每个收到的包的分析结果,只在结束时,显示汇总结果Ping 命令的基本描述Ping 的操作是向某些IP 地址发送一个ICMP Echo 消息,接着该节点返回一个ICMP Echo replay消息。 ICMP消息使用IP 头作为基本控制。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 35 页 - - - - - - - - - 二、实验环境实验一 数据包的捕获与分析1. 联网计算机2.Windows 或 linux 系统3. 在
4、 P中安装协议分析软件(如:Wireshark )4. 物理基础:IEEE802.3 标准的以太网采用的是持续 CSMA 的方式,正是由于以太网采用这种广播信道争用的方式,使得各个站点可以获得其他站点发送的数据。运用这一原理使信息捕获系统能够拦截的我们所要的信5. 工作模式:1) 广播模式(Broad Cast Model) : 它的物理地址(MAC ) 地址是 0Xffffff 的帧为广播帧,工作在广播模式的网卡接收广播帧。2) 多播传送( MultiCast Model) :多播传送地址作为目的物理地址的帧可以被组内的其它主机同时接收,而组外主机却接收不到。但是,如果将网卡设置为多播传送模
5、式,它可以接收所有的多播传送帧,而不论它是不是组内成员。3) 直接模式( Direct Model ) :工作在直接模式下的网卡只接收目地址是自己 MAC地址的帧。4) 混杂模式( Promiscuous Model ) :工作在混杂模式下的网卡接收所有的流过网卡的帧,信包捕获程序就是在这种模式下运行的。实验二网络层实验Ping 程序的设计与实现1. 联网计算机2. Linux 系统3. 系统自带编译环境名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 35 页 - - -
6、 - - - - - - 三、 程序的需求分析与逻辑框图需求分析1、实验一数据包的捕获与分析1.在 P中安装协议分析软件。2.启动 Wireshark协议分析软件,选择抓包菜单项启动实时监视器,开始实时跟踪显示网络数据报文。可根据系统提示修改显示方式。3.调出跟踪存储的历史报文, 选择有代表性的 ETHERNET, IEEE802.3, IP, ICMP ,TCP ,UDP 报文,对照有关协议逐个分析报文各字段的含义及内容。4.设置过滤器属性,如目的地址,源地址,协议类型等。如过滤不需要的网络报文,过滤器允许设置第二层,第三层或第四层的协议字段。2、实验二网络层实验 Ping 程序的设计与实现
7、PING程序是我们使用的比较多的用于测试网络连通性的程序。PING程序给予 ICMP使用 ICMP的回送请求和回送应答来工作。 ICMP是基于 IP 的一个协议,ICMP包通过 IP 的封装之后传递。实现检测网络通畅及速度的ping ,并扩展以下功能:-h 显示帮助信息-b 允许 ping 一个广播地址,只用于IPv4 -t 设置 ttl值,只用于 IPv4 -q 安静模式,不显示每个收到的包的分析结果,只在结束时,显示汇总结果名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,
8、共 35 页 - - - - - - - - - 三、程序的需求分析与逻辑框图逻辑框图1、 总体设计程序分为两大部分:一部分读取收到的所有消息,并输出ICMP Echo replay消息,另一部分每个一秒钟发送一个Echo 消息。另一部分由SIGALARM 信号每秒驱动一次。2、 详细设计mainreadlooprecvfromprocsig_alarmsend为 SIGALARM 建立信号处理程序无限接收循环每秒发送一个 Echo消息1)main 函数设置随同 Echo请求一起发送的可选数据长度处理命令行参数调用 readloop处理分组为SIGALARM 信号建立一个处理程序处理主机名参数
9、名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 35 页 - - - - - - - - - 三、程序的需求分析与逻辑框图逻辑框图2)readloop函数创建套接口设置套接口缓冲区大小发送第一个分组读取返回给 ICMP原始套接口的每个分组记录收到分组的时间调用 proc来处理这些分组 3 )proc 函数 4)send 函数名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - -
10、 - 第 6 页,共 35 页 - - - - - - - - - 三、程序的需求分析与逻辑框图逻辑框图Checksum 开始定义初始化cksum (size 1) 确定 cksum 及 size大小是if (size) 计算校验 cksum,获得结果cksum += *(UCHAR*)buffer; 否结束名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 35 页 - - - - - - - - - 四、程序核心功能的实现机制1、实验一利用协议分析软件跟踪局域网报文,实验
11、内容如下:将安装协议分析软件的PC接入以太网中,跟踪PC 之间的报文,并存入文件以备重新查。设置过滤器过滤网络报文以检测特定数据流。利用协议分析软件的统计工具显示网络报文的各种统计信息。2、实验二Ping 命令的基本描述Ping 的操作是向某些IP 地址发送一个ICMP Echo 消息,接着该节点返回一个ICMP Echo replay消息。ICMP消息使用IP 头作为基本控制。IP 头的格式如下0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-
12、+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checks
13、um| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Version=4 IHL Internet头长 Type of Service = 0 Total Leng
14、th IP包的总长度 Identification, Flags, Fragment Offset 用于 IP 包分段 Time to Live IP包的存活时长 Protocol ICMP = 1 Addresses 发送Echo 消息的源地址是发送Echo reply消息的目的地址, 相反 , 发送Echo 消息的目的地址是发送Echo reply消息的源地址。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 35 页 - - - - - - - - - 四、 程序核心
15、功能的实现机制2、实验二Ping 实际上是使用ICMP中的 ECHO 报文来实现的。Echo 或 Echo Reply 消息格式如下 : 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Code | Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16、| Identifier | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data . +-+-+-+-+- Type echo 消息的类型为8 echo reply 的消息类型为0。Code=0 Checksum 为从 TYPE开始到 IP 包结束的校验和Identifier 如果 code = 0, identifier用来匹配echo 和 echo reply消息Sequence Number 如果 code = 0, identifier用来匹配echo 和
17、echo reply消息功能描述 : 收到 echo 消息必须回应 echo reply 消息。 identifier 和 sequence number 可能被发送echo 的主机用来匹配返回的 echo reply消息。例如 : identifier 可能用于类似于TCP或 UDP的 port 用来标示一个会话, 而 sequence number 会在每次发送echo 请求后递增。收到 echo 的主机或路由器返回同一个值与之匹配名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第
18、9 页,共 35 页 - - - - - - - - - 四、程序核心功能的实现机制2、实验二1、 数据结构的描述1) IP包格式struct ip BYTE Ver_ihl; /版本号与包头长度BYTE TOS; /服务类型WORD Leng; /IP包长度WORD Id; /IP包标示 , 用于辅助 IP 包的拆装 , 本实验不用 , 置零WORD Flg_offset; /偏移量 , 也是用于IP 包的拆装 , 本实验不用 , 置零BYTE TTL; /IP包的存活时间BYTE Protocol; /上一层协议 , 本实验置ICMP WORD Checksum; / 包头校验和, 最初置
19、零 , 等所有包头都填写正确后, 计算并替换。BYTE Saddr4; /源端 IP 地址BYTE Daddr4; /目的端 IP 地址BYTE Data1; /IP包数据; 2)ICMP包格式struct icmp BYTE Type; /ICMP类型 , 本实验用 8: ECHO 0:ECHO REPLY BYTE Code; /本实验置零WORD Checksum; /ICMP包校验和 , 从 TYPE开始 , 直到最后一位用户数据, 如果为字节数为奇数则补充一位WORD ID; /用于匹配ECHO 和 ECHO REPLY 包WORD Seq; /用于标记ECHO 报文顺序BYTE D
20、ata1; /用户数据; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 35 页 - - - - - - - - - 五、程序源代码(核心部分)2、实验二PING.H #ifndef PING_H_ #define PING_H_ #include #include #include #include #include #include /* basic system data types */ #include /* basic socket definitions
21、 */ #include /* timeval for select() */ #include /* timespec for pselect() */ #include /* sockaddr_in and other Internet defns */ #include /* inet(3) functions */ #include #include #include #include #include #include #include #include #include /* for Unix domain sockets */ #include #include #include
22、 #include #ifdef HAVE_SOCKADDR_DL_STRUCT # include #endif #define BUFSIZE 1500 #define MAXLINE 4096 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 35 页 - - - - - - - - - /* globals */ char recvbufBUFSIZE; char sendbufBUFSIZE; int ttl_signal; int ttl_value; cha
23、r *ttl_val; int datalen; /* #bytes of data, following ICMP header */ char *host; int broad_sign=0; int nsent; /* add 1 for each sendto() */ pid_t pid; /* our PID */ int sockfd; int verbose; int daemon_proc; /* set nonzero by daemon_init() */ /* function prototypes */ void proc_v4(char *, ssize_t, st
24、ruct timeval *); void proc_v6(char *, ssize_t, struct timeval *); void send_v4(void); void send_v6(void); void readloop(void); void sig_alrm(int); void tv_sub(struct timeval *, struct timeval *); char * Sock_ntop_host(const struct sockaddr *sa, socklen_t salen); struct addrinfo* host_serv(const char
25、 *host, const char *serv, int family, int socktype); static void err_doit(int errnoflag, int level, const char *fmt, va_list ap); void err_quit(const char *fmt, .); void err_sys(const char *fmt, .); struct proto void (*fproc)(char *, ssize_t, struct timeval *); void (*fsend)(void); struct sockaddr *
26、sasend; /* sockaddr for send, from getaddrinfo */ struct sockaddr *sarecv; /* sockaddr for receiving */ socklen_t salen; /* length of sockaddrs */ int icmpproto; /* IPPROTO_xxx value for ICMP */ *pr; #endif /* PING_H_ */ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第
27、 12 页,共 35 页 - - - - - - - - - PING.C #include ping.h struct proto proto_v4 = proc_v4, send_v4, NULL, NULL, 0, IPPROTO_ICMP ; #ifdef IPV6 struct proto proto_v6 = proc_v6, send_v6, NULL, NULL, 0, IPPROTO_ICMPV6 ; #endif int datalen = 56; /* data that goes with ICMP echo request */ double rtt_min = IN
28、FINITY, rtt_max = -INFINITY, rtt_total = 0, rtt_sqr_total = 0; long long send_count = 0, recv_count = 0; int ttl_flag = 0, broadcast_flag = 0; int ttl = 0; struct timeval tval_start; const char *usage = usage: ping -v -h -b -t ttl -q n t-vtNormal moden t-btBroadcastn t-t ttltSet TTL(0-255)n t-qtQuie
29、t mode; int main(int argc, char *argv) int c; struct addrinfo *ai; opterr = 0; /* dont want getopt() writing to stderr */ while ( (c = getopt(argc, argv, vhbt:q) != -1) switch (c) case v: verbose+; break; case h: puts(usage); return 0; case b: broadcast_flag = 1; break; case t: ttl_flag = sscanf(opt
30、arg, %d, &ttl) & ttl = 0 & ttl ai_canonname, Sock_ntop_host(ai-ai_addr, ai-ai_addrlen), datalen); /* 4initialize according to protocol */ if (ai-ai_family = AF_INET) pr = &proto_v4; #ifdef IPV6 else if (ai-ai_family = AF_INET6) pr = &proto_v6; if (IN6_IS_ADDR_V4MAPPED(&(struct sockaddr_in6 *) ai-ai_
31、addr)-sin6_addr) err_quit(cannot ping IPv4-mapped IPv6 address); #endif else err_quit(unknown address family %d, ai-ai_family); pr-sasend = ai-ai_addr; pr-sarecv = calloc(1, ai-ai_addrlen); pr-salen = ai-ai_addrlen; gettimeofday(&tval_start, NULL); readloop(); exit(0); 名师资料总结 - - -精品资料欢迎下载 - - - - -
32、 - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 35 页 - - - - - - - - - void proc_v4(char *ptr, ssize_t len, struct timeval *tvrecv) int hlen1, icmplen; double rtt; struct ip *ip; struct icmp *icmp; struct timeval *tvsend; ip = (struct ip *) ptr; /* start of IP header */ hlen1 = ip-ip_hl 2;
33、/* length of IP header */ icmp = (struct icmp *) (ptr + hlen1); /* start of ICMP header */ if ( (icmplen = len - hlen1) 8) err_quit(icmplen (%d) icmp_type = ICMP_ECHOREPLY) if (icmp-icmp_id != pid) return; /* not a response to our ECHO_REQUEST */ if (icmplen 16) err_quit(icmplen (%d) icmp_data; tv_s
34、ub(tvrecv, tvsend); rtt = tvrecv-tv_sec * 1000.0 + tvrecv-tv_usec / 1000.0; if (rtt rtt_max) rtt_max = rtt; rtt_total += rtt; rtt_sqr_total += rtt * rtt; recv_count+; if (verbose 0) printf(%d bytes from %s: seq=%u, ttl=%d, rtt=%.3f msn, icmplen, Sock_ntop_host(pr-sarecv, pr-salen), icmp-icmp_seq, ip
35、-ip_ttl, rtt); else if (verbose 1) printf( %d bytes from %s: type = %d, code = %dn, icmplen, Sock_ntop_host(pr-sarecv, pr-salen), icmp-icmp_type, icmp-icmp_code); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 15 页,共 35 页 - - - - - - - - - void proc_v6(char *ptr, ssi
36、ze_t len, struct timeval* tvrecv) #ifdef IPV6 int hlen1, icmp6len; double rtt; struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; struct timeval *tvsend; ip6 = (struct ip6_hdr *) ptr; /* start of IPv6 header */ hlen1 = sizeof(struct ip6_hdr); if (ip6-ip6_nxt != IPPROTO_ICMPV6) err_quit(next header not IP
37、PROTO_ICMPV6); icmp6 = (struct icmp6_hdr *) (ptr + hlen1); if ( (icmp6len = len - hlen1) 8) err_quit(icmp6len (%d) icmp6_type = ICMP6_ECHO_REPLY) if (icmp6-icmp6_id != pid) return; /* not a response to our ECHO_REQUEST */ if (icmp6len 16) err_quit(icmp6len (%d) tv_sec * 1000.0 + tvrecv-tv_usec / 100
38、0.0; if (rtt rtt_max) rtt_max = rtt; rtt_total += rtt; rtt_sqr_total += rtt * rtt; recv_count+; if (verbose 0) printf(%d bytes from %s: seq=%u, hlim=%d, rtt=%.3f msn, icmp6len, Sock_ntop_host(pr-sarecv, pr-salen), icmp6-icmp6_seq, ip6-ip6_hlim, rtt); else if (verbose 1) printf( %d bytes from %s: typ
39、e = %d, code = %dn, icmp6len, Sock_ntop_host(pr-sarecv, pr-salen), icmp6-icmp6_type, icmp6-icmp6_code); #endif /* IPV6 */ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 16 页,共 35 页 - - - - - - - - - unsigned short in_cksum(unsigned short *addr, int len) int nleft = l
40、en; int sum = 0; unsigned short *w = addr; unsigned short answer = 0; while (nleft 1) sum += *w+; nleft -= 2; /* 4mop up an odd byte, if necessary */ if (nleft = 1) *(unsigned char *)(&answer) = *(unsigned char *)w ; sum += answer; /* 4add back carry outs from top 16 bits to low 16 bits */ sum = (su
41、m 16) + (sum & 0 xffff); /* add hi 16 to low 16 */ sum += (sum 16); /* add carry */ answer = sum; /* truncate to 16 bits */ return(answer); void send_v4(void) int len; struct icmp *icmp; icmp = (struct icmp *) sendbuf; icmp-icmp_type = ICMP_ECHO; icmp-icmp_code = 0; icmp-icmp_id = pid; icmp-icmp_seq
42、 = nsent+; gettimeofday(struct timeval *) icmp-icmp_data, NULL); len = 8 + datalen; /* checksum ICMP header and data */ icmp-icmp_cksum = 0; icmp-icmp_cksum = in_cksum(u_short *) icmp, len); sendto(sockfd, sendbuf, len, 0, pr-sasend, pr-salen); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - -
43、- 名师精心整理 - - - - - - - 第 17 页,共 35 页 - - - - - - - - - void send_v6() #ifdef IPV6 int len; struct icmp6_hdr *icmp6; icmp6 = (struct icmp6_hdr *) sendbuf; icmp6-icmp6_type = ICMP6_ECHO_REQUEST; icmp6-icmp6_code = 0; icmp6-icmp6_id = pid; icmp6-icmp6_seq = nsent+; gettimeofday(struct timeval *) (icmp6
44、 + 1), NULL); len = 8 + datalen; /* 8-byte ICMPv6 header */ sendto(sockfd, sendbuf, len, 0, pr-sasend, pr-salen); #endif /* IPV6 */ void readloop(void) int size; char recvbufBUFSIZE; socklen_t len; ssize_t n; struct timeval tval; sockfd = socket(pr-sasend-sa_family, SOCK_RAW, pr-icmpproto); setuid(g
45、etuid(); /* dont need special permissions any more */ size = 60 * 1024; /* OK if setsockopt fails */ setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size); if (ttl_flag) setsockopt(sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl) ; if (broadcast_flag) setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST
46、, &broadcast_flag, sizeof(broadcast_flag) ; sig_alrm(SIGALRM); /* send first packet */ for ( ; ; ) len = pr-salen; n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, pr-sarecv, &len); if (n fproc)(recvbuf, n, &tval); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 18 页
47、,共 35 页 - - - - - - - - - void sig_alrm(int signo) (*pr-fsend)(); send_count+; alarm(1); return; /* probably interrupts recvfrom() */ void sig_int(int signo) struct timeval tval_end; double tval_total; gettimeofday(&tval_end, NULL); tv_sub(&tval_end, &tval_start); tval_total = tval_end.tv_sec * 1000
48、.0 + tval_end.tv_usec / 1000.0; puts(- ping statistics -); printf(%lld packets transmitted, %lld received, %.0lf% packet loss, time %.2lfmsn, send_count, recv_count, (send_count - recv_count) * 100.0 / send_count, tval_total); double rtt_avg = rtt_total / recv_count; printf(rtt min/avg/max/mdev = %.
49、3lf/%.3lf/%.3lf/%.3lf msn, rtt_min, rtt_avg, rtt_max, rtt_sqr_total / recv_count - rtt_avg * rtt_avg); close(sockfd); exit(0); void tv_sub(struct timeval *out, struct timeval *in) if ( (out-tv_usec -= in-tv_usec) tv_sec; out-tv_usec += 1000000; out-tv_sec -= in-tv_sec; 名师资料总结 - - -精品资料欢迎下载 - - - - -
50、 - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 19 页,共 35 页 - - - - - - - - - char * sock_ntop_host(const struct sockaddr *sa, socklen_t salen) static char str128; /* Unix domain is largest */ switch (sa-sa_family) case AF_INET: struct sockaddr_in *sin = (struct sockaddr_in *) sa; if (inet_ntop(AF