Unix/Linux Socket 服務器代碼實例
我們已經看過關於服務器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); } } |