要使進程成為TCP服務器,您需要遵循下面給出的步驟
? ? ? ? - 使用socket()系統(tǒng)調(diào)用創(chuàng)建一個套接字。
? ? ? ? -?使用Bind()系統(tǒng)調(diào)用將套接字綁定到一個地址。對于Internet上的服務器套接字,地址由主機上的端口號組成。
? ? ? ? -?監(jiān)聽與Listen()系統(tǒng)調(diào)用的連接。
? ? ? ? -?使用read()和write()系統(tǒng)調(diào)用發(fā)送和接收數(shù)據(jù)。
現(xiàn)在讓我們將這些步驟以源代碼的形式呈現(xiàn)出來。將這段代碼放到server.c文件中,并用gcc編譯器編譯它。
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.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語句和下面的代碼放入一個無限循環(huán)中。
? ? ? ? - 連接建立后,調(diào)用fork()創(chuàng)建一個新進程。
? ? ? ? -?子進程將關(guān)閉sockfd并調(diào)用doprocessing函數(shù),將新的套接字文件描述符作為參數(shù)傳遞。當兩個進程完成它們的對話時,如doprocessing()返回所示,這個進程就會退出。
? ? ? ? -?父進程關(guān)閉newsockfd。由于所有這些代碼都處于無限循環(huán)中,它將返回到accept語句以等待下一個連接。
#include?<stdio.h>
#include?<stdlib.h>
#include?<unistd.h>
#include?<netdb.h>
#include?<netinet/in.h>
#include?<string.h>
void?doprocessing?(int?sock);
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);
???}
}
int?main(?int?argc,?char?*argv[]?)?{
???int?sockfd,?newsockfd,?portno,?clilen;
???char?buffer[256];
???struct?sockaddr_in?serv_addr,?cli_addr;
???int?n,?pid;
???/*?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?*/
}