Presentation is loading. Please wait.

Presentation is loading. Please wait.

实验讲解 1 、套接字的使用实例. D.E.Comer,D.L.Stevens, TCP/IP 网络互连技术 卷 III: 客户服务器编程和应用 Windows 套接字版 清华大学出版社 清华大学出版社 ServerClient Time.

Similar presentations


Presentation on theme: "实验讲解 1 、套接字的使用实例. D.E.Comer,D.L.Stevens, TCP/IP 网络互连技术 卷 III: 客户服务器编程和应用 Windows 套接字版 清华大学出版社 清华大学出版社 ServerClient Time."— Presentation transcript:

1 实验讲解 1 、套接字的使用实例

2 D.E.Comer,D.L.Stevens, TCP/IP 网络互连技术 卷 III: 客户服务器编程和应用 Windows 套接字版 清华大学出版社 清华大学出版社 ServerClient Time

3 page 3 实验讲解 1 字节顺序 字节顺序 两种字节排序 : 大头 (big-endian) 和小头 (little-endian) 。 小头( Little endian ): 低位字节存于低地址,高位字节存于高地 址处。例: 23F1H , F1 存于 2400H 单元, 23 存于 2401H 单元。 Intel CPU ,大部分小型机使用这种方式。 大头( big endian ) : 低位字节存于高地址,高位字节存于低地址处。 Motorola 的微处理器, IBM 大型机使用这种方式。 小头和大头起源于 Gulliver’ Travels :如何敲开鸡蛋呢?是从大头还 是从小头。 u_long htonl(u_long hostlong); /* 主机序 => 网络序 */ u_long ntohl(u_long netlong); /* 网络序 => 主机序 */ htons, ntohs

4 page 4 实验讲解 1 struct sockaddr_in { short sin_family; /* 协议簇 */ short sin_family; /* 协议簇 */ u_short sin_port; /* 端口号 */ u_short sin_port; /* 端口号 */ struct in_addr sin_addr; /* 网络地址 */ struct in_addr sin_addr; /* 网络地址 */ char sin_zero[8]; /* 给另一主机的网络地址和 IP 地址使用 */ char sin_zero[8]; /* 给另一主机的网络地址和 IP 地址使用 */}; struct in_addr { union { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; /* IP 地址 */ u_long S_addr; /* IP 地址 */ } S_un; /* 4 字节 */ } S_un; /* 4 字节 */} 地址结构 地址结构

5 page 5 实验讲解 1 struct hostent FAR * gethostbyname ( const char FAR*name; const char FAR*name; ) /* 利用主机名或域名获得 IP 地址 ( 网络字节序 ) */ struct hostent { char FAR * h_name; /* official name of host, 如, www.sohu.com, myhost*/ char FAR * h_name; /* official name of host, 如, www.sohu.com, myhost*/www.sohu.com char FAR * FAR * h_aliases; /* alias list, null-terminated */ char FAR * FAR * h_aliases; /* alias list, null-terminated */ short h_addrtype; /* host address type */ short h_addrtype; /* host address type */ short h_length; /* length of address */ short h_length; /* length of address */ char FAR * FAR * h_addr_list; /* list of addresses */ char FAR * FAR * h_addr_list; /* list of addresses */ #define h_addr h_addr_list[0] /* address, for backward compat */ }; 如何把主机名解析为 IP 地址 ? 如何把主机名解析为 IP 地址 ? inet_addr(long ) :将 IP 地址转化为点分十进制。 inet_addr() ,转换 numbers-and-dots 格式的 IP 地址到 unsigned long

6 page 6 实验讲解 1 Gethostbyname() 如果参数为 localhost , 则返回 127.xx.yy.zz 表示回环地址Gethostbyname() 如果参数为 localhost , 则返回 127.xx.yy.zz 表示回环地址 P371P371

7 page 7 实验讲解 1 struct servent FAR * getservbyname ( const char FAR * name; /* 如, HTTP, DayTime; Telnet */ const char FAR * name; /* 如, HTTP, DayTime; Telnet */ const char FAR * proro; /* 协议 ( 可选 ), 如, udp, tcp */ const char FAR * proro; /* 协议 ( 可选 ), 如, udp, tcp */) struct servent { char FAR * s_name; /* official service name */ char FAR * s_name; /* official service name */ char FAR * FAR * s_aliases; /* alias list */ char FAR * FAR * s_aliases; /* alias list */ char FAR * s_proto; /* protocol to use */ char FAR * s_proto; /* protocol to use */ short s_port; /* port # */ short s_port; /* port # */}; 如何把服务名解释为端口号 ? 如何把服务名解释为端口号 ?

8 page 8 实验讲解 1 如何把服务名解释为端口号 ? getservbyport 获得的是 C:\WINDOWS\system32\drivers\etc\servic es 文件中的信息。 daytime 标准服务所用端口为 13 ,使用传输 协议为 TCP 13 十六进制为 0d ,大头顺序为 00 0d ,调试 的时候会看到小头顺序,为 0d 00 ,对应十 进制 3328

9 page 9 实验讲解 1 struct protoentFAR * getprotobyname ( struct protoent FAR * getprotobyname ( const char FAR * name; /* 如, udp, tcp */ const char FAR * name; /* 如, udp, tcp */) struct protoent { char FAR * p_name; /* official protocol name */ char FAR * p_name; /* official protocol name */ char FAR * FAR * p_aliases; /* alias list */ char FAR * FAR * p_aliases; /* alias list */ short p_proto; /* protocol # */ short p_proto; /* protocol # */}; 返回对应于给定协议名的包含名字和协议号的 protoent 结构指针 ppe=Getprotobyname(“tcp”)ppe->p_name=“tcp”Ppe->p_proto=6 如何把协议名转化为协议号 ? 如何把协议名转化为协议号 ?

10 服务器端程序 ( 命令行程序 )

11 #define WSVERSMAKEWORD(2, 2) #define QLEN 5 /* 请求队列长度 */

12 void main(int argc, char *argv[]) {structsockaddr_in fsin; /* the from address of a client*/ char*service = "daytime";/* service name or port number*/ SOCKETmsock, ssock;/* master & slave sockets */ intalen;/* from-address length*/ WSADATA wsadata; switch (argc) { case1: break; case2: service = argv[1]; break; default:errexit("usage: TCPdaytimed [port]\n"); }

13 if (WSAStartup(WSVERS, &wsadata) != 0) errexit("WSAStartup failed\n"); if (WSAStartup(WSVERS, &wsadata) != 0) errexit("WSAStartup failed\n"); msock = passiveTCP(service, QLEN); while (1) { alen = sizeof(struct sockaddr); ssock = accept(msock, (struct sockaddr *)&fsin, &alen); if (ssock = = INVALID_SOCKET) errexit("accept failed: error number %d\n", errexit("accept failed: error number %d\n", GetLastError()); GetLastError()); TCPdaytimed(ssock); TCPdaytimed(ssock); (void) closesocket(ssock); (void) closesocket(ssock);} } (struct sockaddr *)&fsin 把结构 sockaddr_in* 强制转换为结构 sockaddr* , 两者指向的内存区域大小相同

14 SOCKET passiveTCP(const char *service, int qlen) { return passivesock(service, "tcp", qlen); } void TCPdaytimed(SOCKET fd) { char*pts;/* pointer to time string*/ time_tnow;/* current time*/ (void) time(&now); pts = ctime(&now); (void) send(fd, pts, strlen(pts), 0); printf("%s", pts); } ctime 返回字符串指针

15 /*---------------------------------------------------------------------------- * passivesock - allocate & bind a server socket using TCP or UDP * passivesock - allocate & bind a server socket using TCP or UDP *---------------------------------------------------------------------------- */ *---------------------------------------------------------------------------- */ SOCKET passivesock(const char *service, const char *transport, int qlen) { struct servent *pse;/* pointer to service information entry*/ struct protoent *ppe;/* pointer to protocol information entry*/ struct sockaddr_in sin;/* an Internet endpoint address*/ SOCKET s; /* socket descriptor*/ int type; /* socket type (SOCK_STREAM, SOCK_DGRAM) */ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; /* Map service name to port number */ INADDR_ANY 的具体含义是,绑定到 0.0.0.0 。此时,对所有的地址都将 是有效的,如果系统考虑冗余,采用多个网卡的话,那么使用此种 bind , 将在所有网卡上进行绑定。

16 if ( pse = getservbyname(service, transport) ) sin.sin_port = htons(ntohs((u_short)pse->s_port) + portbase); else if ( (sin.sin_port = htons((u_short)atoi(service))) = = 0 ) errexit("can't get \"%s\" service entry\n", service); /* Map protocol name to protocol number */ if ( (ppe = getprotobyname(transport)) = = 0) errexit("can't get \"%s\" protocol entry\n", transport); errexit("can't get \"%s\" protocol entry\n", transport); /* Use protocol to choose a socket type */ /* Use protocol to choose a socket type */ if (strcmp(transport, "udp") = = 0) type = SOCK_DGRAM; type = SOCK_DGRAM;else type = SOCK_STREAM; type = SOCK_STREAM;

17 /* Allocate a socket */ /* Allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if (s = = INVALID_SOCKET) errexit("can't create socket: %d\n", GetLastError()); /* Bind the socket */ /* Bind the socket */ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) = = SOCKET_ERROR) errexit("can't bind to %s port: %d\n", service, GetLastError()); if (type = = SOCK_STREAM && listen(s, qlen) = = SOCKET_ERROR) errexit("can't listen on %s port: %d\n", service, GetLastError()); return s; }

18 客户端程序

19 Int main(int argc, char *argv[]) { char*host = "localhost";/* host to use if none supplied*/ char*service = "daytime";/* default service port*/ WSADATA wsadata; switch (argc) { case 1: host = "localhost"; break; case 3: service = argv[2]; /* FALL THROUGH */ case 2: host = argv[1]; break; default: fprintf(stderr, "usage: TCPdaytime [host [port]]\n"); exit(1); } Host 是服务器名字,域名, service 是服务器提供的某个标准服务

20 if (WSAStartup(WSVERS, &wsadata) != 0) /* 启动某版本的 DLL */ errexit(“WSAStartup failed\n”); TCPdaytime(host, service); /* 建立连接并传输数据 */ WSACleanup(); /* 卸载某版本的 DLL */ printf(“ 按任意键继续...”); getchar(); return 0;/* exit */ } SAStartup() WSAStartup() 参数 1 为版本号 参数 2 存放关于 WSA 的描述信息

21 Void TCPdaytime(const char *host, const char *service) { charbuf[LINELEN+1];/* buffer for one line of text */ SOCKETs;/* socket descriptor */ intcc;/* recv character count*/ s = connectTCP(host, service); /* 建立连接 */ cc = recv(s, buf, LINELEN, 0); while( cc != SOCKET_ERROR && cc > 0) { buf[cc] = '\0';/* ensure null-termination*/ (void) fputs(buf, stdout); cc = recv(s, buf, LINELEN, 0); } closesocket(s); }

22 SOCKET connectTCP(const char *host, const char *service ) { return connectsock( host, service, "tcp"); } 指定使用 TCP 连接

23 SOCKET connectsock(const char *host, const char *service, const char *transport ) { struct hostent*phe;/* pointer to host information entry*/ struct servent*pse;/* pointer to service information entry*/ struct protoent *ppe;/* pointer to protocol information entry*/ struct sockaddr_in sin;/* an Internet endpoint address*/ ints, type;/* socket descriptor and socket type*/ memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; /* Map service name to port number */ if ( pse = getservbyname(service, transport) ) sin.sin_port = pse->s_port; else if ( (sin.sin_port = htons((u_short)atoi(service))) = = 0 ) errexit("can't get \"%s\" service entry\n", service); 根据 transport 参数生成 socket ,根据 host 和 service 建立连接

24 /* Map host name to IP address, allowing for dotted decimal */ if ( phe = gethostbyname(host) ) memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) = = INADDR_NONE) errexit("can't get \"%s\" host entry\n", host); /* Map host name to IP address, allowing for dotted decimal */ if ( phe = gethostbyname(host) ) memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); else if ( (sin.sin_addr.s_addr = inet_addr(host)) = = INADDR_NONE) errexit("can't get \"%s\" host entry\n", host); /* Map protocol name to protocol number */ if ( (ppe = getprotobyname(transport)) = = 0) errexit("can't get \"%s\" protocol entry\n", transport); /* Use protocol to choose a socket type */ if (strcmp(transport, "udp") = = 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if (s = = INVALID_SOCKET) errexit("can't create socket: %d\n", GetLastError()); /* Map protocol name to protocol number */ if ( (ppe = getprotobyname(transport)) = = 0) errexit("can't get \"%s\" protocol entry\n", transport); /* Use protocol to choose a socket type */ if (strcmp(transport, "udp") = = 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /* Allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if (s = = INVALID_SOCKET) errexit("can't create socket: %d\n", GetLastError());

25 /* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) = = SOCKET_ERROR) errexit("can't connect to %s.%s: %d\n", host, service, GetLastError()); /* Connect the socket */ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) = = SOCKET_ERROR) errexit("can't connect to %s.%s: %d\n", host, service, GetLastError()); return s; } // connectsock

26 ==== 完 ====


Download ppt "实验讲解 1 、套接字的使用实例. D.E.Comer,D.L.Stevens, TCP/IP 网络互连技术 卷 III: 客户服务器编程和应用 Windows 套接字版 清华大学出版社 清华大学出版社 ServerClient Time."

Similar presentations


Ads by Google