并发网络服务器 + 网络编程

并发网络服务器:

  • 基本概念解释

多进程并发服务器

togglesp.c

void sigchld_handler(int sig) {  
  while (waitpid(-1, 0, WNOHANG) > 0); 
  return; 
}

 int main(int argc, char **argv) {
    int listen_sock, conn_sock, port;
    socklen_t clientlen=sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    if (argc != 2) {   …   }
    port = atoi(argv[1]);
    signal(SIGCHLD, sigchld_handler);
    listen_sock = open_listen_sock(port);
    while (1) {
        conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
        if (fork() == 0) { 
           close(listen_sock); 
           toggle(conn_sock);      /* Child process services client */
           close(conn_sock);      
           exit(0);       
        }
       close(conn_sock);
    }
}

特点:父子共享打开文件表,但不共享用户地址空间。
优缺点
优点:每个进程都有独立的地址空间,进程间不会相互影响,有较好的可靠性和安全性
缺点:进程间共享状态信息变得麻烦,IPC机制开销很高,进程间数据共享低效

基于多线程并发服务器

togglest.c:

int main(int argc, char **argv) { 

    int listen_sock, *conn_sock_p, port;
    socklen_t clientlen=sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    pthread_t tid;  
    if (argc != 2) {。。。    }

    port = atoi(argv[1]);
    listen_sock = open_listen_sock(port);
    while (1) {
        conn_sock_p = malloc(sizeof(int));
        *conn_sock_p = accept(listen_sock, (SA *) &clientaddr, &clientlen);
        pthread_create(&tid, NULL, serve_client, conn_sock_p); 
    }
}

void * serve_client (void *vargp) {  
    int conn_sock = *((int *)vargp);
    pthread_detach(pthread_self()); 
    free(vargp);
    toggle(conn_sock);
    close(conn_sock);

    return NULL;
}

预线程化并发服务器

  1. 基本思想
    预先创建一批工作者线程,每次建立一个连接,工作者线程就领取一个任务,负责与一个客户端通信以消除服务器运行过程中创建、撤销线程的开销.


    image.png

任务池定义(task_pool.c、task_pool.h)

生产者/消费者模型

# inpos、outpos分别是缓冲区写入、读出指针
# mutex:为互斥信号量
# avail、ready是同步信号量

typedef struct {
    int *socks;         /* Buffer array */         
    int cnt;            /* Maximum number of cell */
    int inpos;          /* buf[inpos] is first available cell */
    int outpos;         /* buf[outpos] is fist item */
    sem_t mutex;      /* Protects accesses to socks */
    sem_t avail;       /* Counts available cells */
    sem_t ready;      /* Counts ready items */
} task_pool_t;

缓冲区初始化

void task_pool_init(task_pool_t *tp, int n)
{
    tp->socks = Calloc(n, sizeof(int)); 
    tp->cnt = n;                     /* socks holds max of n items */
    tp->inpos= tp->outpos = 0;           /* Empty socks iff inpos== outpos */
    sem_init(&tp->mutex, 0, 1);       /* Binary semaphore for locking */
    sem_init(&tp->avail, 0, cnt);       /* Initially, socks has cnt empty cell */
    sem_init(&tp->ready, 0, 0);        /* Initially, socks has zero data items */
}

读写缓冲区

void task_insert (task_pool_t *tp, int item){  

    sem_wait(&tp->avail);           /* Wait for available cell */
    sem_wait(&tp->mutex);          /* Lock the shared variable tail pointer */
    tp->socks[tp->inpos] = item;        /* Insert the item */
    tp-> inpos =(tp-> inpos +1)%(tp->cnt); /* adjuset tail point */
    sem_post(&tp->mutex);          /* Unlock the buffer */
    sem_post(&tp->ready);          /* Announce available item */
}

int task_remove(task_pool_t *tp){。。。}

预线程化服务器代码(togglest_pre.c)

int main(int argc, char **argv) { 
    int i, listen_sock, conn_sock, port;
    socklen_t clientlen=sizeof(struct sockaddr_in);
    struct sockaddr_in clientaddr;
    pthread_t tid;  

    if (argc != 2) { 。。。    }
    port = atoi(argv[1]);
    task_pool_init(&tp, SBUFSIZE);
    listen_sock = open_listen_sock(port);

    for (i = 0; i < NTHREADS; i++)  /* Create worker threads */
        pthread_create(&tid, NULL, serve_client, NULL);
        while (1) { 
          conn_sock = accept(listen_sock, (SA *) &clientaddr, &clientlen);
          task_insert(&tp, conn_sock);    /* Insert conn_sock in task pool */
    }
}

void * serve_client(void *vargp) {  

    pthread_detach(pthread_self()); 
    while (1) { 
       int conn_sock = task_remove(&tp); 
       toggle(conn_sock);
       close(conn_sock);
    }
}

网络编程:

套接字、


套接字编程模型

结构:网卡、TCP协议、套接字(Socket)
套接字:含有进程接收信息的完整地址(Socket地址:IP地址、端口号)

  • Internet连接客户端与服务器的网卡,
  • TCP/IP协议软件连接Socket与网卡,
  • 套接字接口连接进程与Socket,
image.png

TCP连接整合了以上两个工具,tcp连接是连接通讯双方套接字的一条通信线路.一条TCP连接实际上就是一个文件描述符,可用read/write或send/recv进行数据收发.

  • TCP连接实例
    服务器端口号:规定为80
    客户端端口号:随机分配,12345


    image.png

字节序、

  • 网络序(网络序):高位在低地址字节


    大端模式
  • 主机序(小端模式):低位在低地址字节


    小端模式
  • 主机序与网络序的转换
    unsigned long int htonl(unsigned long int hostlong);
    unsigned short int htons(unsigned short int hostshort);
    返回:网络序的值。
    unsigned long int ntohl(unsigned long int netlong);
    unsigned short int ntohs(unsiged short int netshort);
    返回:主机序的值。

  • IP地址
    由32位整数网络序0x8002c2f2转换成点分十进制128.2.193.242
    128=0x80,2=0x02,193=0xc2,242=0xf2
    转换函数:
    int inet_aton(const char *cp, struct in_addr *inp);
    char *inet_ntoa(struct in_addr in);
    a: 字符串 n:32位整数

网络通信API函数:

编程框架

(一)客户端
(1)创建套接字
int socket(int domain, int type , int protocol);
示例:client_sock = socket(AF_INET , SOCK_STREAM, 0);
(2) connect 函数
int connect (int client_sock , struct sockaddr *serv_addr , int addrlen);
(3)包装函数open_client_sock

(二)服务器端
(1)创建
int socket(int domain, int type , int protocol);
(2)绑定
int bind(int serv_sock, struct sockaddr *my_addr , int addrlen);
(3)监听
int listen(int serv_sock, int backlog);
(4)接受连接请求
int accept(int listen_sock, struct sockaddr *addr , int *addrlen);
包装函数:open_listen_sock

服务器与客户端连接
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 网络编程 一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运...
    go以恒阅读 1,992评论 0 6
  • 大纲 一.Socket简介 二.BSD Socket编程准备 1.地址 2.端口 3.网络字节序 4.半相关与全相...
    VD2012阅读 2,276评论 0 5
  • socket通信原理 socket又被叫做套接字,它就像连接到两端的插座孔一样,通过建立管道,将两个不同的进程之间...
    jiodg45阅读 1,121评论 0 1
  • 网络模型 物理层 物理层表示的是比特流传输,通常包括串口/COM口、并行/LPT口、USB、网线接口、电话线接口;...
    秋风弄影阅读 705评论 0 2
  • 第一章 引言和网络编程基础知识 1.1 分别简述OSI参考模型和TCP/IP模型,并阐述他们之间的对应关系 1.2...
    V0W阅读 5,294评论 0 9