• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
            數據加載中……

            多進程并發服務器編程


            一、實驗目的

            理解進程的創建和終止方法;

            熟悉父進程與子進程對描述符的操作過程;

            學會編寫基本的多進程并發服務器程序和客戶程序。

            二、實驗平臺

            ubuntu-8.04操作系統

            三、實驗內容

            編寫多進程并發服務器程序和客戶程序,具體功能如下:

            1、服務器等待接收客戶的連接請求,一旦連接成功則顯示客戶地址,接著接收客戶端的名稱并顯示;然后接收來自該客戶的字符串,每當收到一個字符串時,顯示該字符串,并將字符串按照愷撒密碼的加密方式(K=3)進行加密,再將加密后的字符發回客戶端;之后,繼續等待接收該客戶的信息,直到客戶關閉連接。要求服務器具有同時處理多個客戶請求的能力。

            2、客戶首先與相應的服務器建立連接;接著接收用戶輸入的客戶端名稱,并將其發送給服務器;然后繼續接收用戶輸入的字符串,再將字符串發送給服務器,同時接收服務器發回的加密后的字符串并顯示。之后,繼續等待用戶輸入字符串,直到用戶輸入Ctrl+D,客戶關閉連接并退出。

            四、實驗原理

            前面所實現的服務器/客戶程序中,服務器每次只能處理一個客戶的請求,他雖然很簡單但效率低下。在實際應用中,這樣的服務器不能滿足實際需求,并發技術可以極大地提高服務器的處理能力和響應速度。

            TCP并發服務器的工作流程見圖6.1所示:

            6.1TCP并發服務器

            1、創建進程

            可以通過調用forkvfork函數來創建新進程。

            1fork函數

            -------------------------------------------------------------------
            #include<sys/types.h>

            #include <unistd.h>

            pid_t fork(void)

            返回:父進程中返回子進程的進程ID,子進程返回0-1出錯

            -------------------------------------------------------------------


            • fork后,子進程和父進程繼續執行fork()函數后的指令。子進程是父進程的副本。子進程擁有父進程的數據空間、堆棧的副本。但父、子進程并不共享這些存儲空間部分。如果代碼段是只讀的,則父子進程共享代碼段。如果父子進程同時對同一文件描述字操作,而又沒有任何形式的同步,則會出現混亂的狀況;

            • 父進程中調用fork之前打開的所有描述字在函數fork返回之后子進程會得到一個副本。fork后,父子進程均需要將自己不使用的描述字關閉。

            2vfork函數

            -------------------------------------------------------------------
            #include<sys/types.h>

            #include <unistd.h>

            pid_tvfork(void)

            返回:父進程中返回子進程的進程ID,子進程返回0-1出錯

            -------------------------------------------------------------------


            • forkvfork函數的基本區別在于當使用vfork()創建新進程時,父進程將被暫時阻塞,而子進程則可以借用父進程的地址空間,直到子進程退出,至此父進程才繼續執行。

            2、終止進程

            進程的終止存在兩個可能:

            1)父進程先于子進程終止;

            2)子進程先于主進程終止。

            • 對于后者,系統內核為子進程保留一定的狀態信息:進程ID、終止狀態、CPU時間等;當父進程調用waitwaitpid函數時,獲取這些信息。

            • 當子進程正常或異常終止時,系統內核向其父進程發送SIGCHLD信號;缺省情況下,父進程忽略該信號,或者提供一個該信號發生時即被調用的函數。

            exit()函數:

            -------------------------------------------------------------------
            #include<stdlib.h>

            void exit(int status);

            -------------------------------------------------------------------

            exit()函數用于終止調用進程。關閉所有子進程打開的描述符,向父進程發送SIGCHLD信號,并返回狀態。

            父進程可通過調用wait()waitpid()函數獲得子進程的終止信息。

            wait()函數:

            -------------------------------------------------------------------
            #include<sys/types.h>

            #include <sys/wait.h>

            pid_t wait(int*stat_loc);

            返回:終止子進程的ID-成功;-1-出錯;stat_loc存儲子進程的終止狀態(一個整數);

            -------------------------------------------------------------------

            如果沒有終止的子進程,但是有一個或多個正在執行的子進程,則該函數將堵塞,直到有一個子進程終止或者wait被信號中斷時,wait返回。

            當調用該系統調用時,如果有一個子進程已經終止,則該系統調用立即返回,并釋放子進程所有資源。


            waitpid()函數:

            -------------------------------------------------------------------
            #include<sys/types.h>

            #include <sys/wait.h>

            pid_t waitpid(pid_t pid, int*stat_loc, int option);

            返回:終止子進程的ID-成功;-1-出錯;stat_loc存儲子進程的終止狀態;-------------------------------------------------------------------


            pid=-1,option=0時,該函數等同于wait,否則由參數pidoption共同決定函數行為,其中pid參數意義如下:

              • -1:要求知道任何一個子進程的返回狀態(等待第一個終止的子進程);

              • >0:要求知道進程號為pid的子進程的狀態;

              • <-1:要求知道進程號為pid的絕對值的子進程的終止狀態

            Option最常用的選項是WNOHANG,它通知內核在沒有已終止進程時不要堵塞。

            調用waitwaitpid函數時,正常情況下,可能會有以下幾種情況:

              • 阻塞(如果其所有子進程都還在運行);

              • 獲得子進程的終止狀態并立即返回(如果一個子進程已終止,正等待父進程存取其終止狀態);

              • 出錯立即返回(如果它沒有任何子進程)


            五、實驗步驟

            1、登陸進入ubuntu操作系統,新建一個文件,命名為mproc_server.c,新建另一個文件,命名為mproc_client.c

            2、在mproc_server.cmproc_client.c中編寫相應代碼并保存。

            3、打開一個終端,執行命令進入mproc_server.cmproc_client.c所在目錄。

            4、執行命令gccomproc_servermproc_server.c生成可執行文件mproc_server

            5、執行命令gccomproc_clientmproc_client.c生成可執行文件mproc_client

            6、執行命令./mproc_server,運行服務器端。

            7、打開第2終端,執行命令進入mproc_server.cmproc_client.c所在目錄。

            8、執行命令./mproc_client127.0.0.1,模擬客戶1

            9、打開第3終端,執行命令進入mproc_server.cmproc_client.c所在目錄。

            10、執行命令./mproc_client127.0.0.1,模擬客戶2

            11、程序運行結果如下:

            服務器端:


            客戶1



            客戶2


            12、在客戶端按下Ctrl+D,關閉客戶連接。

            13、認真分析源代碼,體會多進程并發服務器程序的編寫。

            六、參考程序

            1mproc_server.c內容如下:

            1. #include <stdio.h>  
            2. #include <stdlib.h>  
            3. #include <string.h>  
            4. #include <unistd.h>  
            5. #include <sys/types.h>  
            6. #include <sys/socket.h>  
            7. #include <netinet/in.h>  
            8. #include <arpa/inet.h>  
            9.   
            10. #define PORT 1234  
            11. #define BACKLOG 5  
            12. #define MAXDATASIZE 1000  
            13. void process_cli(int  connfd, struct sockaddr_in client);  
            14.   
            15. main()  
            16. {  
            17. int  listenfd, connfd;  
            18. pid_t  pid;  
            19. struct  sockaddr_in  server;  
            20. struct sockaddr_in  client;  
            21. int  len;  
            22.   
            23. if ((listenfd =socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
            24. perror("Creatingsocket failed.");  
            25. exit(1);  
            26. }  
            27.   
            28. int opt =SO_REUSEADDR;  
            29. setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  
            30. bzero(&server,sizeof(server));  
            31. server.sin_family=AF_INET;  
            32. server.sin_port=htons(PORT);  
            33. server.sin_addr.s_addr= htonl (INADDR_ANY);  
            34. if (bind(listenfd,(struct sockaddr *)&server, sizeof(server)) == -1) {  
            35. perror("Bind()error.");  
            36. exit(1);  
            37. }  
            38.   
            39. if(listen(listenfd,BACKLOG)== -1){  
            40. perror("listen() error\n");  
            41. exit(1);  
            42. }  
            43. len=sizeof(client);  
            44.   
            45. while(1)  
            46. {  
            47. if ((connfd =accept(listenfd,(struct sockaddr *)&client,&len))==-1) {  
            48. perror("accept() error\n");  
            49. exit(1);  
            50. }  
            51. if ((pid=fork())>0){  
            52. close(connfd);  
            53. continue;  
            54. }  
            55. else if (pid==0) {  
            56. close(listenfd);  
            57. process_cli(connfd, client);  
            58. exit(0);  
            59. }  
            60. else {  
            61. printf("fork()error\n");  
            62. exit(0);  
            63. }  
            64. }  
            65. close(listenfd);  
            66. }  
            67.   
            68. void process_cli(int connfd, struct sockaddr_in client)  
            69. {  
            70. int num;  
            71. char  recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];  
            72. printf("Yougot a connection from %s. ",inet_ntoa(client.sin_addr) );  
            73. num = recv(connfd,cli_name, MAXDATASIZE,0);  
            74. if (num == 0)  
            75. {  
            76. close(connfd);  
            77. printf("Client disconnected.\n");  
            78. return;  
            79. }  
            80. cli_name[num - 1] ='\0';  
            81. printf("Client'sname is %s.\n",cli_name);  
            82.   
            83. while (num =recv(connfd, recvbuf, MAXDATASIZE,0)) {  
            84. recvbuf[num] ='\0';  
            85. printf("Receivedclient( %s ) message: %s",cli_name, recvbuf);  
            86. int i = 0;  
            87. for (i = 0;i < num - 1; i++) {  
            88. if((recvbuf[i]>='a'&&recvbuf[i]<='z')||(recvbuf[i]>='A'&&recvbuf[i]<='Z'))  
            89. {  
            90. recvbuf[i]=recvbuf[i]+ 3;  
            91. if((recvbuf[i]>'Z'&&recvbuf[i]<='Z'+3)||(recvbuf[i]>'z'))  
            92. recvbuf[i]=recvbuf[i]- 26;  
            93. }  
            94. sendbuf[i] =recvbuf[i];  
            95. }  
            96. sendbuf[num - 1]= '\0';  
            97.   
            98. send(connfd,sendbuf,strlen(sendbuf),0);  
            99. }  
            100. close(connfd);  
            101. }  


             

            2mproc_client.c內容如下:

            1. #include <stdio.h>  
            2. #include <stdlib.h>  
            3. #include <unistd.h>  
            4. #include <string.h>  
            5. #include<sys/types.h>  
            6. #include<sys/socket.h>  
            7. #include<netinet/in.h>  
            8. #include <netdb.h>  
            9.   
            10. #define PORT 1234  
            11. #define MAXDATASIZE100  
            12. void process(FILE*fp, int sockfd);  
            13. char *getMessage(char* sendline,int len, FILE* fp);  
            14.   
            15. int main(int argc,char *argv[])  
            16. {  
            17. int fd;  
            18. struct hostent  *he;  
            19. struct sockaddr_in  server;  
            20.   
            21. if (argc !=2) {  
            22. printf("Usage:%s <IP Address>\n",argv[0]);  
            23. exit(1);  
            24. }  
            25.   
            26. if((he=gethostbyname(argv[1]))==NULL){  
            27. printf("gethostbyname() error\n");  
            28. exit(1);  
            29. }  
            30. if((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){  
            31. printf("socket()error\n");  
            32. exit(1);  
            33. }  
            34.   
            35. bzero(&server,sizeof(server));  
            36. server.sin_family =AF_INET;  
            37. server.sin_port=htons(PORT);  
            38. server.sin_addr= *((struct in_addr *)he->h_addr);  
            39.   
            40. if(connect(fd,(struct sockaddr *)&server,sizeof(server))==-1){  
            41. printf("connect() error\n");  
            42. exit(1);  
            43. }  
            44.   
            45. process(stdin,fd);  
            46.   
            47. close(fd);  
            48. }  
            49.   
            50. void process(FILE *fp, int  sockfd)  
            51. {  
            52. char sendline[MAXDATASIZE],recvline[MAXDATASIZE];  
            53. int num;  
            54.   
            55. printf("Connected to server. \n");  
            56. printf("Input client's name : ");  
            57. if (fgets(sendline, MAXDATASIZE, fp) == NULL) {  
            58. printf("\nExit.\n");  
            59. return;  
            60. }  
            61. send(sockfd,sendline, strlen(sendline),0);  
            62. while(getMessage(sendline, MAXDATASIZE, fp) != NULL) {  
            63. send(sockfd,sendline, strlen(sendline),0);  
            64.   
            65. if ((num =recv(sockfd, recvline, MAXDATASIZE,0)) == 0) {  
            66. printf("Server terminated.\n");  
            67. return;  
            68. }  
            69.   
            70. recvline[num]='\0';  
            71. printf("Server Message: %s\n",recvline);  
            72.   
            73. }  
            74. printf("\nExit.\n");  
            75. }  
            76.   
            77. char  *getMessage(char*  sendline,int len, FILE*  fp)  
            78. {  
            79. printf("Inputstring to server:");  
            80. return(fgets(sendline,MAXDATASIZE, fp));  
            81. }  

             

            posted on 2012-07-05 14:24 tqsheng 閱讀(565) 評論(0)  編輯 收藏 引用

            综合久久久久久中文字幕亚洲国产国产综合一区首 | 国内精品久久久久久久亚洲| 狠狠色婷婷久久一区二区| 久久精品一区二区三区中文字幕 | 欧美精品福利视频一区二区三区久久久精品| 久久ww精品w免费人成| 久久久久久久女国产乱让韩| 亚洲国产成人久久笫一页| 青草久久久国产线免观| 久久综合视频网站| 人人妻久久人人澡人人爽人人精品| 欧美精品一区二区久久| 香蕉久久夜色精品国产尤物| 无码精品久久一区二区三区 | 亚洲中文字幕久久精品无码APP | 老司机午夜网站国内精品久久久久久久久 | 999久久久无码国产精品| 亚洲AV无一区二区三区久久| 少妇内射兰兰久久| 精品国产91久久久久久久| 久久精品草草草| 久久午夜综合久久| 亚洲综合伊人久久综合| 久久久久久综合一区中文字幕| 秋霞久久国产精品电影院| 久久精品无码专区免费| 久久久久久精品久久久久| 久久综合香蕉国产蜜臀AV| 国产精品va久久久久久久| 久久久99精品成人片中文字幕| 超级97碰碰碰碰久久久久最新| 精品国产VA久久久久久久冰| 久久久久九九精品影院| 精品久久久久久无码专区| 久久久久久久亚洲精品| 日本欧美久久久久免费播放网| 国产91久久精品一区二区| 区久久AAA片69亚洲| 国产精品成人99久久久久| 青草国产精品久久久久久| 久久这里只精品99re66|