1. 迭代服务器 & 并发服务器
服务器按照 处理方式 来看可以分为:
1.1 迭代服务器
迭代服务器只能一次处理一个客户的请求。也就是说在服务器响应一个客户请求时,如果有另一个客户发起请求是不能得到及时响应的。下图是一个典型的迭代服务器处理流程。
1.2 并发服务器
并发服务器则能同时处理多个客户端请求。下图是一个基于多进程模型的并发服务器处理流程。
2. 多进程并发服务器
1. 客户端调用connet发起连接
2. 服务器accept阻塞返回,建立连接成功
3. 服务器端调用fork()创建子进程
4. 服务器端关闭连接套接字,子进程关闭监听套接字
5. 子进程中处理客户请求,父进程继续处于accept()阻塞监听状态。
3. 简单实现
源码可以到: Github连接上进行下载。
服务器端源码:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#define SERV_PORT 8000
#define MAXLINE 1024
int main()
{
int fd, confd, clientaddrlen, revlen, i;
struct sockaddr_in serveraddr, clientaddr;
char str[INET_ADDRSTRLEN];
char buf[MAXLINE];
pid_t pid;
//1. 创建一个socket
fd = socket(AF_INET, SOCK_STREAM, 0);
//2. 绑定一个端口
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERV_PORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(fd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
//3. 设置监听
listen(fd, 20);
printf("Accepting Connecting...\n");
while(1)
{
//4.接受链接
clientaddrlen = sizeof(clientaddr);
confd = accept(fd, (struct sockaddr*)&clientaddr, &clientaddrlen);
pid = fork();
if(pid == 0)
{
close(fd);
while(1)
{
revlen = read(confd, buf, MAXLINE);
if(revlen == 0)
{
printf("closed\n");
break;
}
printf("client: %s\t port: %d\n",
inet_ntop(AF_INET, &clientaddr.sin_addr, str, sizeof(str)),
ntohs(clientaddr.sin_port));
i = 0;
while(i < revlen)
{
buf[i] = toupper(buf[i]);
++i;
}
write(confd, buf, revlen);
}
close(confd);
return 0;
}
else if(pid > 0)
{
close(confd);
}
else
{
printf("fork err\n");
}
}
close(fd);
return 0;
}
测试用客户端源码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
//sockaddr_in IPv4
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
//1. 创建一个套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//2. 链接到本机8000端口服务器
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
while(fgets(buf, MAXLINE, stdin) != NULL)
{
//3. 向服务器发送数据
write(sockfd, buf, strlen(buf));
//4. 读取服务器的回传数据
n = read(sockfd, buf, MAXLINE);
printf("Response from server:\n");
write(STDOUT_FILENO, buf, n);
}
//5. 关闭套接字描述符
close(sockfd);
return 0;
}