Unix 套接字 - 服务器示例
要使进程成为 TCP 服务器,您需要遵循下面给出的步骤 −
使用 socket() 系统调用创建套接字。
使用 bind() 系统调用将套接字绑定到地址。对于 Internet 上的服务器套接字,地址由主机上的端口号组成。
使用 listen() 系统调用监听连接。
使用 accept() 系统调用接受连接。此调用通常会阻塞,直到客户端连接到服务器为止。
使用 read() 和 write() 系统调用发送和接收数据。
现在让我们将这些步骤以源代码的形式呈现。将此代码放入文件 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 ",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。由于整个代码处于无限循环中,它将返回到 accept 语句以等待下一个连接。
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> void doprocessing (int sock); 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 */ }
以下代码片段展示了doprocessing函数的简单实现。
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 ",buffer); n = write(sock,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } }