前言:刚开始学网络编程,都会先写一个客户端和服务端,不知道你们有没有试一下:再打开一下客户端,是连不上服务端的。还有一个问题不知道你们发现没:有时启服务器,会提示“Address already in use”,过一会就好了,想过为啥么?在这篇博客会解释这个问题。
但现实的服务器都会连很多客户端的,像阿里服务器等,所以这篇主要介绍如何实现并发服务器,主要通过三种方式:进程、线程和select函数来分别实现。
一、进程实现并发服务器
先说下什么是并发服务器吧?不是指有多个服务器同时运行,而是可以同时连接多个客户端。
先简单说下原理吧,先画个图,如下:
先要搞清楚通信的流程,图上参数说明:
lfd:socket函数的返回值,就是监听描述符
cfd1/cfd2/cfd3:accept函数的返回值,用通信的套接字
server:服务器
client:客户端
socket通信过程中,总共有几个套接字呢?答:三个,客户端一个,服务器两个。
根据上图来大致说明一下流程:
客户端创建一个套接字描述符,用于通信,服务器先用socket函数创建套接字,用于监听客户端,然后调用accept函数,会返回一个套接字,用于通信的。图上就是,client1先通过cfd与server建立连接,然后与cfd1建立连接通信,这时lfd就空闲了,再监听客户端,client2再与lfd连接,再跟cfd2通信。client3也是如此。
现在问题就是。如何创建多个进程与客户端通信呢?通过循环创建子进程就可以实现这个问题
服务端程序,如下:
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <unistd.h>
#include "wrap.h"
#define MAXLINE 8192
#define SERV_PORT 8000
void do_sigchild(int num)
{
while (waitpid(0, NULL, WNOHANG) > 0)
;
}
int main(void)
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i, n;
pid_t pid;
struct sigaction newact;
newact.sa_handler = do_sigchild;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGCHLD, &newact, NULL); //建立信号,处理子进程退出
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
// int opt = 1;
//setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //端口复用
bzero(&servaddr, sizeof(s