总体来说,服务器的运行模式大体有两类:循环服务器和并发服务器。所谓的循环服务器就是说他给客户端提供的服务时一个接着一个的,不能同时服务,也就是说当一个用户使用服务器的时候,其他用户不没能使用只能等待。这显然不符合实际服务器的要求,而并发服务器就可以很好地解决这个问题。并发服务器能够同时为多个客户端服务,同时并发服务的能力是服务器性能的一个重要指标。
并发服务器的实现总体有以下几种方法:
① 服务器和每个接收到的客户机进行连接,创建一个新的子进程处理这个客户机请求。
② 服务器预先创建多个子进程,由子进程处理客户机请求。这种方式叫做“预创建”服务器。
③ 服务器用函数select实现对多个客户机连接的多路复用。
④ 超级服务器激活的服务器
这里我们主要讨论第一种实现,我们分为两种实现方式:利用子进程实现,利用线程的方式实现。这里服务器端的功能就是接受客户端的数据,并在服务器屏幕上打印出来,而且要求客户机可以主动断开链接,服务器能够为多个客户机服务。
利用子进程方式实现,服务器端代码:
/*server_fork.c*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
/*定义通讯端口*/
#define MYPORT 4000
/*定义服务器端等待队列长度*/
#define BACKLOG 10
/*定义数据缓冲区大小*/
#define MAXDATASIZE 1024
/*定义客户端发给服务器端断开链接的信号*/
#define FINISH "close"
int main(void)
{
int sock_fd,new_fd;
int numbytes;
int n;
int sin_size;
char buf[MAXDATASIZE];
/*IP地址数据结构*/
struct sockaddr_in server_ip,client_ip;
/*创建套接字*/
if( (sock_fd=socket(AF_INET,SOCK_STREAM,0)) == -1 )
{
perror("socket");
exit(1);
}
/*设置协议族为IPv4,端口为自定义端口,地址为本地任意可用IP地址*/
server_ip.sin_family = AF_INET;
server_ip.sin_port = htons(MYPORT);
server_ip.sin_addr.s_addr = htonl(INADDR_ANY);
n = 1;
/*设置套接字选项,使其可以重复使用端口*/
setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int));
/*绑定地址和端口信息*/
if( bind(sock_fd,(struct sockaddr *)&server_ip,sizeof(struct sockaddr)) == -1 )
{
perror("bind");
exit(1);
}
/*监听来自客户端的链接,队列长度为BACKLOG*/
if( listen(sock_fd,BACKLOG) == -1 )
{
perror("listen");
exit(1);
}
/*主操作部分*/
while(1)
{
sin_size = s