1 /* timeserv.c a socket -based time of day server 访问显示时间 2 */ 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <netdb.h> 9 #include <time.h> 10 #include <strings.h> 11 12 #define PORTNUM 13000 //端口 13 #define HOSTLEN 256 14 #define oops(msg) {perror(msg); exit(1);} 15 16 int main(int argc ,char* argv[]) { 17 struct sockaddr_in saddr; 18 /***************************************************************************** 19 * strcut sockaddr 在socket domain 为 AF_INET domain,时 socketaddr结构定义为: 20 * struct sockadr_in{ 21 * unsigned short int sin_family; //代指协议族,在socket编程中只能为AF_INET.为调用socket()时的domain参数,即AF_XXXX的值 22 * uint16_t sin_port; //为使用的port编号 23 * struct in_addr sin_addr; //sin_addr.s_addr为IP地址 24 * unsigned char sin_zero[8]; //未使用 25 * } 26 *****************************************************************************/ 27 struct hostent * hp; 28 /***************************************************************************** 29 * strcut hostent { 30 * char *h_name; //主机的规范名,eg:www.google.com的规范名其实是www.I.google.com 31 * char **h_aliases; //主机别名,eg:www.google.com就是google的别名,也许有很多别名 32 * int h_addrtype; //表示主机ip类型,ipv4(AF_INET) , ipv6(AF_INET6) 33 * int h_length; //表示主机ip长度 34 * char **h_addr_list; //表示主机ip地址,注意这个是以网络字节序存储的,需要打印用inet_ntop()函数;并且 h_addr为h_addr_list的第一地址 35 } 36 *****************************************************************************/ 37 char hostname[HOSTLEN]; //address 38 int sock_id, sock_fd; //line id, file desc 39 FILE *sock_fp; //use socket as stream 40 char * ctime(); //convert secs to string 41 time_t thetime; //the time we report 42 /*** Step1: ask kernel for a socket***/ 43 sock_id = socket(PF_INET, SOCK_STREAM, 0); //get a socket 44 /*sockid = socket(int domain, int type, int protocol) 45 *domain 通信域:PF_INET用于Internet socket; type类型:socket的类型,SOCK_STREAM类似管道; protocol 协议: 所用协议,默认为0*/ 46 if(sock_id==-1) 47 oops("socket"); 48 49 /*** Step2: bind address to socket, Address is host ,port ***/ 50 bzero((void*)&saddr, sizeof(saddr)); 51 gethostname(hostname, HOSTLEN); //获取主机名 52 hp=gethostbyname(hostname); //获取主机信息 get info about host 53 54 bcopy((void*)hp->h_addr, (void*)&saddr.sin_addr, hp->h_length);//复制ip到saddr中 55 saddr.sin_port=htons(PORTNUM); //填入端口 fill in socket port 56 /*其中htons函数,是进行htons转换,改变大端设置为小端结构*/ 57 saddr.sin_family=AF_INET; //填入协议族 58 59 if(bind(sock_id, (struct sockaddr*)&saddr, sizeof(saddr)) !=0 ) //绑定ip地址端口号到socket上 60 oops("bind"); 61 62 /*** Step3: allow incoming calls with Qsize=1 on socket***/ 63 if(listen(sock_id, 1)!=0) 64 /**************************************************************************** 65 listen请求内核允许指定的socket接收接入呼叫,监听socket上的连接,并不是所用类型的socket都能接收接入呼叫,但SOCK_STREAM类型是可以的。第二个参数指出接收队列的长度 66 ****************************************************************************/ 67 oops("listen"); 68 69 /* 70 * main loop: accept(), write(), close() 71 */ 72 while(1) { 73 sock_fd = accept(sock_id, NULL, NULL); //wait for call 74 printf("Wow! got a call! "); 75 if(sock_fd == -1) 76 oops("accept"); 77 78 sock_fp = fdopen(sock_fd, "w"); //we'll write to the 79 if(sock_fp == NULL) //socket as a stream 80 oops("fdopen"); 81 thetime = time(NULL); 82 83 fprintf(sock_fp, "The time here is ..."); 84 fprintf(sock_fp, "%s", ctime(&thetime)); 85 fclose(sock_fp); 86 } 87 return 0; 88 }
运行操作方法:
1.gcc timeserv.c -o timeserv
2. ./timeserv& 启动服务以"&"符号结尾,所以shell将运行它但不调用wait调用。
3.可以用telnet连接此服务器上:
telnet 'hostname' 13000 (hostname 可以用echo $HOSTNAME 来查看)