• 一个epoll事件实现的高并发服务/客户端(C语言实现,服务端存储基于hashtable)


      代码路径:https://github.com/prophetss/epoll-event

      之前实现了一个简单高效的hashtable(点这里),这里结合epoll基于reactor模型实现了一个高并发服务器。大体思想是将epoll接到的每一个服务请求存储到hashtable里来管理,每一个请求都可以设置独立的回调函数。具体可以先看代码,注释已经写得很详细。代码实现了一个简单server端实例,client端我写了两个例子,一个为Linux C实现,一个是Python实现(主要为了可以在不同系统跑)。C client是fork了产生1024个进程来模仿高并发请求,在同一台机子上测试结果平均每秒读响应34万多次,参考结果如下:

    Python client是创建1000个线程来分别不断发送数据,在局域网内两台机子上测试平均结果为每秒31000次左右。比上面慢的多,分析主要原因应该是网络IO瓶颈造成的,参考结果如下:

    最后将client代码贴到下面充下长度..

    client(C):

      1 #include <unistd.h>
      2 #include <sys/mman.h>
      3 #include <netinet/in.h>
      4 #include <semaphore.h>
      5 #include <sys/types.h>
      6 #include <sys/socket.h>
      7 #include <arpa/inet.h>
      8 #include <fcntl.h>
      9 #include <wait.h>
     10 #include <string.h>
     11 #include <netdb.h>
     12 #include <stdlib.h>
     13 #include "error.h"
     14 
     15 
     16 /*进程共享文件用于统计创建进程个数*/
     17 #define PFILE_NAME    "count"
     18 
     19 /*需要创建的进程数*/
     20 #define PROCESS_NUM        100
     21 
     22 /*每个进程请求次数*/
     23 #define REQUEST_TIMES    10000
     24 
     25 
     26 struct shared {
     27     sem_t mutex;    /*信号量用于加锁*/
     28     int count;        /*进程个数*/
     29 } shared;
     30 
     31 
     32 void request(const char *server_ip, int server_port)
     33 {
     34     struct sockaddr_in client_addr;
     35     bzero(&client_addr, sizeof(client_addr));
     36     client_addr.sin_family = AF_INET;
     37     client_addr.sin_addr.s_addr = INADDR_ANY;
     38     client_addr.sin_port = htons(0);
     39     
     40     int client_socket = socket(AF_INET, SOCK_STREAM, 0);
     41     if(client_socket < 0) exit_throw("create client socket fail");
     42     
     43     struct sockaddr_in server_addr;
     44     bzero((char *)&server_addr, sizeof(server_addr));
     45 
     46     server_addr.sin_family = AF_INET;
     47 
     48     struct hostent *server = gethostbyname(server_ip);
     49     if(!server) exit_throw("fail to get host name");
     50 
     51     bcopy((char *)server->h_addr, (char *)&server_addr.sin_addr.s_addr, server->h_length);
     52 
     53     server_addr.sin_port = htons(server_port);
     54     socklen_t server_addr_len = sizeof(server_addr);
     55 
     56     if(connect(client_socket, (struct sockaddr*) &server_addr, server_addr_len) == -1 ) {
     57         exit_throw("connent to server fail");
     58     }
     59 
     60     int pid = getpid();
     61 
     62     char content[64] = {0};
     63     sprintf(content, "%s, pid:%d
    ", "i am client!", pid);
     64     for (int i = 0; i < REQUEST_TIMES; ++i) {
     65         send(client_socket, content, strlen(content), 0);
     66         usleep(10000);    //10ms
     67     }
     68 
     69     close(client_socket);
     70 
     71     exit(0);
     72 }
     73 
     74 /*
     75  * 参数1为serverip,参数2为server端口号
     76  */
     77 int main(int argc,char *argv[])
     78 {
     79     if(argc != 3) exit_throw("parameter error!
    ");
     80 
     81     char *server_ip = argv[1];
     82     int server_port = atoi(argv[2]);
     83 
     84     struct shared *psh;
     85 
     86     /*创建共享文件*/
     87     int fd = open(PFILE_NAME, O_RDWR | O_CREAT | O_TRUNC, 0666);
     88     /*初始化0*/
     89     int ret_len = write(fd, &shared, sizeof(struct shared));
     90     if (ret_len != sizeof(struct shared)) {
     91         exit_throw("write error!
    ");
     92     }
     93     /*映射内存*/
     94     psh = mmap(NULL, sizeof(struct shared), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     95     close(fd);
     96 
     97     sem_init(&psh->mutex, 1, 1);
     98     
     99     int i, pid[PROCESS_NUM];
    100     for (i = 0; i < PROCESS_NUM; i++) {
    101         pid_t fpid = fork();
    102         if (0 == fpid) {
    103             pid[i]=getpid();
    104             sem_wait(&psh->mutex);
    105             psh->count++;
    106             printf("%d processes was created!
    ", psh->count);
    107             sem_post(&psh->mutex);
    108             request(server_ip, server_port);
    109         }
    110         else if (fpid > 0) {
    111         }
    112         else {
    113             exit_throw("fork error!");
    114         }
    115     }
    116 
    117     /*等待所有子进程创建完毕*/
    118     while (psh->count < PROCESS_NUM) {
    119         sleep(0);
    120     }
    121 
    122     wait(NULL);
    123 
    124     remove(PFILE_NAME);
    125     
    126     printf("exit all!
    ");
    127 
    128     return 0;
    129 }

    client(Python ):

     1 # -*- coding: UTF-8 -*-
     2 
     3 import threading
     4 import random
     5 import socket
     6 import time
     7 import sys
     8 
     9 class tThread (threading.Thread):
    10     counter = 0
    11     def __init__(self, threadID, name, ip, port):
    12         threading.Thread.__init__(self)
    13         self.threadID = threadID
    14         self.name = name
    15         self.ip = ip
    16         self.port = port
    17     def run(self):
    18         print("开始线程:", self.name+str(self.threadID))
    19         sendData(self.name, self.threadID, self.counter, self.ip, self.port)
    20         print("退出线程:", self.name+str(self.threadID))
    21 
    22 def sendData(name, threadID, counter, ip, port):
    23     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    24     s.connect((ip, port))
    25     for i in range(1000000):
    26         counter = counter + 1
    27         current_time = time.asctime()
    28         try:
    29             s.send(("%d times: i am %s and now is %s.
    "%(counter, str(name)+str(threadID), str(current_time))).encode('utf-8'))
    30         except Exception as e:
    31             pass
    32     s.close()
    33 
    34 '''
    35     参数1:server端ip
    36     参数2:server端口号
    37 '''
    38 if __name__ == '__main__':
    39     threads = []
    40     for i in range(1000):
    41         t = tThread(i, "Thread", sys.argv[1], int(sys.argv[2]))
    42         t.start()
    43         threads.append(t)
    44     for x in threads:
    45         x.join()

     2018-07-08 19:29:25更新:添加测试

  • 相关阅读:
    数据库表与视图的区别
    maven中snapshot版本和正式版本的区别
    @Retention注解
    java泛型以及通配符
    git 删除了本不应该删除的commit 如何恢复
    ES group分组聚合的坑
    solution for 1006 中国剩余定理
    solution for POJ 1001
    ondraw() 和dispatchdraw()的区别
    android几种定时器机制及区别(转载整理)
  • 原文地址:https://www.cnblogs.com/prophet-ss/p/9180977.html
Copyright © 2020-2023  润新知