客戶端一服務器模型中的基本操做是事務。一個客戶端一服務器事務由如下四步組成。html
hostname -i
可查詢主機的點分十進制地址:naslookup localhost
查看域名:www.baidu.com
爲例,查看對應IP地址:基於socket 使用教材的csapp.h csapp.c,實現daytime(13)服務器(端口咱們使用13+後三位學號)和客戶端 服務器響應消息格式是 「客戶端IP:XXXX 服務器實現者學號:XXXXXXXX 當前時間: XX:XX:XX」
一個客戶端至少查詢三次時間的截圖測試截圖
至少兩個客戶端查詢時間的截圖測試截圖
git
把課上練習3的daytime服務器分別用多進程和多線程實現成併發服務器並測試
多進程代碼:編程
#include <sys/time.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include<strings.h> #include<ctype.h> #include<errno.h> #include<sys/wait.h> #include<errno.h> #include <time.h> #define PORT 13330 #define BACKLOG 1 #define MAXRECVLEN 1024 int main(int argc, char *argv[]) { char buf[MAXRECVLEN]; int listenfd, connectfd; /* socket descriptors */ pid_t pid; pid_t pids[10]; struct sockaddr_in server; /* server's address information */ struct sockaddr_in client; /* client's address information */ socklen_t addrlen; /* Create TCP socket */ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { /* handle exception */ perror("socket() error. Failed to initiate a socket"); exit(1); } /* set socket option */ int opt = SO_REUSEADDR; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) { /* handle exception */ perror("Bind() error."); exit(1); } if(listen(listenfd, BACKLOG) == -1) { perror("listen() error. \n"); exit(1); } addrlen = sizeof(client); int i; for(i = 0; i< 10;i++){ pid = fork(); if(pid > 0){ continue; } pids[i] = pid; } while(1){ if((connectfd=accept(listenfd,(struct sockaddr *)&client, &addrlen))==-1) { perror("accept() error. \n"); exit(1); } struct timeval tv; gettimeofday(&tv, NULL); time_t t; t=time(NULL); printf("客戶端IP: %s. \n",inet_ntoa(client.sin_addr)); printf("服務器實現者學號:%d\n",20155330); printf("當前時間: %s\n",ctime(&t)); } int iret=-1; while(1) { iret = recv(connectfd, buf, MAXRECVLEN, 0); if(iret>0) { //printf("%s\n", buf); }else { close(connectfd); break; } /* print client's ip and port */ send(connectfd, buf, iret, 0); /* send to the client welcome message */ } close(listenfd); /* close listenfd */ return 0; }
測試結果:
瀏覽器
多線程代碼:安全
#include<stdio.h> #include<stdlib.h> #include<pthread.h> #include<sys/socket.h> #include<sys/types.h> //pthread_t , pthread_attr_t and so on. #include<netinet/in.h> //structure sockaddr_in #include<arpa/inet.h> //Func : htonl; htons; ntohl; ntohs #include<assert.h> //Func :assert #include<string.h> //Func :memset #include<unistd.h> //Func :close,write,read #include<ctype.h> #include<arpa/inet.h> #include <time.h> #define SOCK_PORT 13330 #define BUFFER_LENGTH 1024 #define MAX_CONN_LIMIT 5 //MAX connection limit static void Data_handle(void * sock_fd); struct sockaddr_in s_addr_in; struct sockaddr_in s_addr_client; int sockfd; int main() { int sockfd_server; int fd_temp; int client_length; sockfd_server = socket(AF_INET,SOCK_STREAM,0); //ipv4,TCP assert(sockfd_server != -1); memset(&s_addr_in,0,sizeof(s_addr_in)); s_addr_in.sin_family = AF_INET; s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); //trans addr from uint32_t host byte order to network byte order. s_addr_in.sin_port = htons(SOCK_PORT); //trans port from uint16_t host byte order to network byte order. fd_temp = bind(sockfd_server,(struct scokaddr*)(&s_addr_in),sizeof(s_addr_in)); if(fd_temp == -1) { fprintf(stderr,"bind error!\n"); exit(1); } fd_temp = listen(sockfd_server,MAX_CONN_LIMIT); if(fd_temp == -1) { fprintf(stderr,"listen error!\n"); exit(1); } while(1) { pthread_t thread_id; client_length = sizeof(s_addr_client); sockfd = accept(sockfd_server,(struct sockaddr*)(&s_addr_client),&client_length); time_t t = time(0); char tmp[64]; strftime( tmp, sizeof(tmp), "%Y/%m/%d %X %A\n\t", localtime(&t) ); send(sockfd,tmp,strlen(tmp),0); close(sockfd); //close a file descriptor. if(sockfd == -1) { fprintf(stderr,"Accept error!\n"); continue; //ignore current socket ,continue while loop. } if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1) { fprintf(stderr,"pthread_create error!\n"); break; //break while loop } } //Clear int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection. assert(ret != -1); return 0; } static void Data_handle(void * sock_fd) { int fd = *((int *)sock_fd); int i_recvBytes; char data_recv[BUFFER_LENGTH]; printf("服務器實現者:20155330\n"); printf("客戶端IP:%s\n",inet_ntoa(s_addr_client.sin_addr)); pthread_exit(NULL); //terminate calling thread! }
測試結果:
服務器
gcc XXX.c -lpthread -o XXX
進行編譯。A.若t==0則ZF=1網絡
B.若t<0,則CF=1多線程
C.若t<0,則SF=1併發
D.若(a<0==b<0)&&(t<0 != a<0), 則OF=1app
E.若(a<0==b<0)&&(t<0 != a<0), 則CF=1
F.leaq指令不影響條件碼寄存器
G.cmp指令不影響條件碼寄存器
A.leaq 6(%rax), %rdx; %rdx中值爲6+x
B.leaq 6(%rax), %rdx; %rdx中值爲6x
C.leaq 7(%rax, %rax,8), %rdx; %rdx中值爲9x
D.leaq 7(%rax, %rax,8), %rdx; %rdx中值爲63x
E.leaq 7(%rax, %rax,8), %rdx; %rdx中值爲15x
leaq 7(%rax, %rax,8), %rdx
中%rdx的值爲7+9xA.能夠用char[][] 來傳遞argv
B.進程調用了exec系列函數後,pid會變
C.進程調用了exec系列函數後,代碼會改變。
D.system()和exec系列等價。
E.exec系列函數中帶e的要傳入環境變量參數
F.exec系列函數中帶v的要傳入環境變量參數
A.getpid()
B.getppid()
C.getcpid()
D.fork()
B.(%rax)的值是0x100
C.(%rax)的值是0x104
D.(%rax)的值是0xFF
E.4(%rax)的值是0xAB
F.(%rax,%rcx,4)的值是0xAB
G.(%rax,%rcx,4)的值是0x104
理解狀況:(rb,ri,s) 操做數值M[R[rb]+R[ri]·s]
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 0/0 | 1/1 | 10/10 | |
第二週 | 63/63 | 1/2 | 8/18 | |
第三週 | 31/94 | 1/3 | 18/36 | |
第四周 | 265/329 | 1/4 | 17/53 | |
第五週 | 106/435 | 2/6 | 18/71 | |
第六週 | 211/646 | 2/8 | 21/92 | |
第七週 | 1420/2066 | 2/10 | 17/109 | |
第八週 | 1061/3127 | 1/11 | 17/126 |
嘗試一下記錄「計劃學習時間」和「實際學習時間」,到期末看看能不能改進本身的計劃能力。這個工做學習中很重要,也頗有用。
耗時估計的公式
:Y=X+X/N ,Y=X-X/N,訓練次數多了,X、Y就接近了。
計劃學習時間:18小時
實際學習時間:17小時