我們已經看過關於伺服器socket建立的教學,為了使進程TCP伺服器端需要執行以下步驟:
建立一個socket使用socket() 系統呼叫.
使用bind()系統呼叫通訊端系結到一個地址。對於網際網路上的伺服器通訊端,地址包括主機的埠號。
使用listen()系統呼叫連線監聽。
accept() 系統呼叫形式接受連線。此呼叫通常會阻塞,直到有用戶端與伺服器連線。
傳送和接收資料,使用read() 和 write() 系統呼叫。
現在要把上面這些步驟的形式寫成原始碼。把這個程式碼寫server.c檔案並用gcc編譯器編譯。
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here process will * go in sleep mode and will wait for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); /* Accept actual connection from the client */ newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* If connection is established then start communicating */ bzero(buffer,256); n = read( newsockfd,buffer,255 ); if (n < 0) { perror("ERROR reading from socket"); exit(1); } printf("Here is the message: %s\n",buffer); /* Write a response to the client */ n = write(newsockfd,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } return 0; } |
為了使伺服器能夠同時處理多個連線,我們在上面的程式碼進行以下更改:
將accept語句和下面的程式碼在一個無限迴圈。
建立連線後,呼叫fork()建立一個新的進程。
子進程將關閉sockfd中致電doprocessing函式,通過新的通訊端檔案描述符作為引數。當兩個進程已經完成了他們對話中表示由doprocessing()返回,這個過程簡單地退出。
父進程關閉newsockfd。因為所有這些程式碼是在一個無限迴圈,它接受語句將返回到等待下一個連線。
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here * process will go in sleep mode and will wait * for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); while (1) { newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* Create child process */ pid = fork(); if (pid < 0) { perror("ERROR on fork"); exit(1); } if (pid == 0) { /* This is the client process */ close(sockfd); doprocessing(newsockfd); exit(0); } else { close(newsockfd); } } /* end of while */ } |
Here is the simple implementation of doprocessing function.
void doprocessing (int sock) { int n; char buffer[256]; bzero(buffer,256); n = read(sock,buffer,255); if (n < 0) { perror("ERROR reading from socket"); exit(1); } printf("Here is the message: %s\n",buffer); n = write(sock,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } } |