多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區(qū)平臺 聯系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > 互聯網 > 幾種服務器模型

幾種服務器模型

來源:程序員人生   發(fā)布時間:2014-09-05 22:01:33 閱讀次數:2473次

TCP測試用客戶程序

每次運行客戶程序,在命令行參數指定服務器的ip地址,端口,發(fā)起連接的子進程數,和一個待發(fā)送的字符串數據,客戶程序將模擬多個客戶根據指定的子進程數創(chuàng)建子進程來并發(fā)的連接到服務器,并發(fā)送數據,服務器收到數據后都原樣的回發(fā)給客戶,是一點典型的回射服務器。

#include "net.h" char *addr = NULL; char *request = NULL; unsigned int port; int connCount; int clientfd; void client_deal() { char *buf = NULL; int len; Tcp_connect(addr, port, &clientfd); if (sendAll(clientfd, request, strlen(request)) > 0) { len = recvAll(clientfd, (void**)&buf); if (len > 0) { buf[len] = 0; printf("%s ", buf); } } freePtr(buf); Close(clientfd); exit(0); } int main(int argc, char **argv) { if (argc != 5) { printf("use [ip] [port] [connCount] [request] "); exit(-1); } addr = argv[1]; port = atoi(argv[2]); connCount = atoi(argv[3]); request = argv[4]; for (int i=0; i<connCount; ++i) { if (fork() == 0) { client_deal(); } } while (wait(NULL) > 0); if (errno != ECHILD) { perror("wait error"); exit(-1); } return 0; }


1.迭代服務器

在處理完成某個客戶的請求之后才轉向下一個客戶,比較少見,雖然總的服務時間稍慢,但需要進程控制

#include "net.h" int listenfd; void server_deal() { char *buf = NULL; ssize_t size; int clifd; Accept(listenfd, NULL, NULL, &clifd); printf("有新連接 "); if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); Close(clifd); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); while (1) { server_deal(); } return 0; }

2.TCP多進程并發(fā)服務器

每個客戶fork出一個子進程并發(fā)的去處理請求,總服務器時間稍短,fork子進程比較耗費CPU時間

#include "net.h" int listenfd; int clifd; void server_deal() { char *buf = NULL; ssize_t size; if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); Close(clifd); exit(0); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); while (1) { Accept(listenfd, NULL, NULL, &clifd); printf("有新連接 "); if (fork() == 0) { Close(listenfd); server_deal(); } Close(clifd); } return 0; }


3.TCP預先派生子進程服務器

與之前的每一個客戶請求臨時fork一個進程處理不同,在啟動的時候就fork出一些子進程,優(yōu)點是節(jié)省了臨時fork的開銷,缺點是父進程在啟動階段要先知道預先派生的子進程數,如果連接較多而無可用子進程,那么客戶請求超過了連接排隊數就可能會被忽略

#include "net.h" const int PROCESS_COUNT = 5; int listenfd; void server_deal() { int clifd; char *buf = NULL; ssize_t size; Accept(listenfd, NULL, NULL, &clifd); printf("子進程%ld有新連接 ", (long)getpid()); if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); Close(clifd); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); for (int i=0; i<PROCESS_COUNT; ++i) { if (fork() == 0) { while (1) { server_deal(); } } } while (1); return 0; }


4.TCP預先派生子進程服務器,accept使用文件上鎖保護

因為某些內核實現中不允許多個進程引用對同一個監(jiān)聽套接字調用accept,所以對accept加鎖成為原子操作為對上一種模型的改進

#include "net.h" const int PROCESS_COUNT = 5; int listenfd; int lock_fd; struct flock lock_it, unlock_it; void my_lock_init(const char *pathname) { char lock_file[1024]; strncpy(lock_file, pathname, sizeof(lock_file)); lock_fd = Mkstemp(lock_file); Unlink(lock_file); lock_it.l_type = F_WRLCK; lock_it.l_whence = SEEK_SET; lock_it.l_start = 0; lock_it.l_len = 0; unlock_it.l_type = F_UNLCK; unlock_it.l_whence = SEEK_SET; unlock_it.l_start = 0; unlock_it.l_len = 0; } void my_lock_wait() { while (fcntl(lock_fd, F_SETLKW, &lock_it) < 0) { if (errno == EINTR) continue; else printErrExit("my_lock_wait error"); } } void my_lock_release() { while (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0) { if (errno == EINTR) continue; else printErrExit("my_lock_release error"); } } void server_deal() { int clifd; char *buf = NULL; ssize_t size; my_lock_wait(); Accept(listenfd, NULL, NULL, &clifd); printf("子進程%ld有新連接 ", (long)getpid()); my_lock_release(); if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); Close(clifd); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); my_lock_init("/tmp/lock.XXXXXX"); for (int i=0; i<PROCESS_COUNT; ++i) { if (fork() == 0) { while (1) { server_deal(); } } } while (1); return 0; }


5.TCP預先派生子進程服務器,accept使用線程上鎖保護

與上一模型類似,采用多進程間共享線程鎖進行的方式對預先派生進程服務器的改進

#include "net.h" const int PROCESS_COUNT = 5; int listenfd; pthread_mutex_t *mptr; void my_lock_init() { int fd; pthread_mutexattr_t mattr; fd = Open("/dev/zero", O_RDWR, 0); mptr = (pthread_mutex_t*)Mmap(0, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); Close(fd); pthread_mutexattr_init(&mattr); pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(mptr, &mattr); } void my_lock_wait() { pthread_mutex_lock(mptr); } void my_lock_release() { pthread_mutex_unlock(mptr); } void server_deal() { int clifd; char *buf = NULL; ssize_t size; my_lock_wait(); Accept(listenfd, NULL, NULL, &clifd); printf("子進程%ld有新連接 ", (long)getpid()); my_lock_release(); if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); Close(clifd); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); my_lock_init(); for (int i=0; i<PROCESS_COUNT; ++i) { if (fork() == 0) { while (1) { server_deal(); } } } while (1); return 0; }

6.TCP預先派生子進程服務器,主進程傳遞描述符

主進程中accept后將已連接的套接字通過進程間通信的方式傳遞給預先派生的空閑進程,預先派生的進程處理完成后向主進程發(fā)送消息,主進程負責維護所有預先派生進程的狀態(tài)以及可用數目

#include "net.h" #define THREAD_COUNT 5 typedef struct { pid_t pid; int pipefd; int status; long count; } Child; int listenfd; int navail; Child carr[THREAD_COUNT]; int tmp_conn_count; void sig_int(int sig) { int i; int sum = 0; sum += tmp_conn_count; printf("tmp_conn_count:%d ", tmp_conn_count); for (i=0; i<THREAD_COUNT; i++) { sum += carr[i].count; printf("carr[%d]'s conn is %ld ", i, carr[i].count); } printf("sum is %d ", sum); exit(-1); } void server_deal(int i) { int ret; int clifd; char *buf = NULL; char c = 'w'; int size; struct strrecvfd recv_stru; while (1) { recvfd(STDERR_FILENO, &clifd); if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); Close(clifd); freePtr(buf); buf = NULL; write(STDERR_FILENO, &c, 1); } } void child_make(int i) { int sockfd[2]; pid_t pid; Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); //Socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd); if ( (pid = fork()) > 0) { Close(sockfd[1]); carr[i].pipefd = sockfd[0]; carr[i].status = 0; carr[i].count = 0; carr[i].pid = pid; } else { if (dup2(sockfd[1], STDERR_FILENO) < 0) printErrExit("dup2 error"); Close(sockfd[1]); Close(sockfd[0]); Close(listenfd); carr[i].pipefd = sockfd[1]; server_deal(i); } } void temp_child(int clifd) { char *buf = NULL; int size; if (fork() > 0) { Close(clifd); ++tmp_conn_count; } else { if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); Close(clifd); freePtr(buf); exit(0); } } int main() { int maxfd; fd_set rset, master; int nsel; int clifd; int i; printf("pid:%d ", getpid()); Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); FD_ZERO(&rset); FD_SET(listenfd, &master); maxfd = listenfd; tmp_conn_count = 0; for (i=0; i<THREAD_COUNT; i++) { child_make(i); FD_SET(carr[i].pipefd, &master); if (maxfd < carr[i].pipefd) maxfd = carr[i].pipefd; } navail = THREAD_COUNT; Signal(SIGINT, sig_int); while (1) { printf("navail: %d ", navail); rset = master; nsel = Select(maxfd+1, &rset, NULL, NULL, NULL); if (FD_ISSET(listenfd, &rset)) { Accept(listenfd, NULL, NULL, &clifd); if (navail > 0) { for (i=0; i<THREAD_COUNT; i++) if (carr[i].status == 0) break; //向子進程傳遞連接上來的套接字描述符 sendfd(carr[i].pipefd, clifd); carr[i].status = 1; --navail; } else { temp_child(clifd); } if (--nsel == 0) continue; } for(int i=0; i<THREAD_COUNT; i++) { if (FD_ISSET(carr[i].pipefd, &rset)) { char c; read(carr[i].pipefd, &c, sizeof(c)); carr[i].count++; carr[i].status = 0; ++navail; if (--nsel == 0) break; } } } return 0; }

客戶程序創(chuàng)建30個子進程連接時,向服務器進程發(fā)送SIGINT信號查看各個進程服務數目的分布






7.TCP多線程并發(fā)服務器

對于每一個客戶請求創(chuàng)建一個線程來處理,與多進程并發(fā)服務器相比,創(chuàng)建線程比創(chuàng)建進程的開銷更低

#include "net.h" int listenfd; void* server_deal(void *arg) { int clifd = *((int*)arg); printf("clifd: %d ", clifd); char *buf = NULL; ssize_t size; if ( (size = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, size); freePtr(buf); freePtr(arg); Close(clifd); } int main() { Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); while (1) { int clifd; pthread_t tid; int *arg = NULL; Accept(listenfd, NULL, NULL, &clifd); printf("有新連接 "); arg = (int*)Malloc(sizeof(int)); *arg = clifd; Pthread_create(&tid, NULL, server_deal, arg); } return 0; }


8.TCP預先創(chuàng)建線程服務器,每個線程各自accept

#include "net.h" #define THREAD_COUNT 5 int listenfd; pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; void server_deal() { int clifd; int len; char *buf = NULL; pthread_mutex_lock(&mylock); Accept(listenfd, NULL, NULL, &clifd); pthread_mutex_unlock(&mylock); if ( (len = recvAll(clifd, (void**)&buf)) > 0) sendAll(clifd, buf, len); Close(clifd); } void* handler(void *arg) { while (1) { server_deal(); } } int main() { pthread_t tid; Tcp_listen("INADDR_ANY", 9999, 5, &listenfd); for (int i=0; i<THREAD_COUNT; ++i) Pthread_create(&tid, NULL, handler, NULL); while (1); return 0; }


net.h頭文件

#ifndef MY_NET_H #define MY_NET_H #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #include <string.h> #include <sys/select.h> #include <sys/time.h> #include <errno.h> #include <signal.h> #include <sys/wait.h> #include <pthread.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <stropts.h> #define MAXLINE 4096 #define SA struct sockaddr #define LISTENEQ 10 //清除數據 //ptr 指針 void freePtr(void *ptr) { if (ptr != NULL) free(ptr); } //打印錯誤信息并終止進程 //errStr 錯誤字符串 void printErrExit(const char* errStr) { if (errStr != NULL) perror(errStr); printf("進程pid:%d ", getpid()); exit(-1); } int Open(const char *pathname, int flags, mode_t mode) { int fd; while ( (fd = open(pathname, flags, mode)) < 0) { if (errno == EINTR) continue; printErrExit("Open error"); } return fd; } int Socketpair(int domain, int type, int protocol, int sv[2]) { if (socketpair(domain, type, protocol, sv) < 0) printErrExit("Socketpair error"); } void Signal(int signum, sighandler_t handler) { if (signal(signum, handler) == SIG_ERR) printErrExit("Signal error"); } int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int ret; while ( (ret = select(nfds, readfds, writefds, exceptfds, timeout)) < 0) { if (errno == EINTR) continue; printErrExit("Select error"); } return ret; } ssize_t Read(int fd, void *buf, size_t count) { int ret; while ( (ret = read(fd, buf, count)) < 0) { if (errno == EINTR) continue; printErrExit("Read error"); } return ret; } ssize_t Write(int fd, const void *buf, size_t count) { int ret; while ( (ret = write(fd, buf, count)) < 0) { if (errno == EINTR) continue; printErrExit("Write error"); } return ret; } void Dup2(int oldfd, int newfd) { while (dup2(oldfd, newfd) < 0) { if (errno == EINTR) continue; printErrExit("Dup2 error"); } } void *Mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { void *ptr; if ( (ptr = mmap(addr, length, prot, flags, fd, offset)) == MAP_FAILED) printErrExit("Mmap error"); return ptr; } int Mkstemp(char *path) { int lock_fd; if ( (lock_fd = mkstemp(path)) < 0) printErrExit("Mkstemp error"); return lock_fd; } void Unlink(const char *pathname) { if (unlink(pathname) < 0) printErrExit("Unlink error"); } void* Malloc(size_t size) { void *ret = NULL; if ( (ret = malloc(size)) == NULL) printErrExit("Malloc error"); return ret; } int sendfd(int fd, int fd_to_send) { struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; char buf = ' '; iov.iov_base = &buf; iov.iov_len = 1; cmsg = (struct cmsghdr*)malloc(CMSG_LEN(sizeof(int))); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int*)CMSG_DATA(cmsg) = fd_to_send; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsg; msg.msg_controllen = CMSG_LEN(sizeof(int)); msg.msg_flags = 0; while (sendmsg(fd, &msg, 0) < 0) { if (errno == EINTR) continue; return -1; } return 0; } int recvfd(int fd, int *fd_to_recv) { struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; char buf; int ret; iov.iov_base = &buf; iov.iov_len = 1; cmsg = (struct cmsghdr*)malloc(CMSG_LEN(sizeof(int))); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsg; msg.msg_controllen = CMSG_LEN(sizeof(int)); msg.msg_flags = 0; while ( (ret = recvmsg(fd, &msg, 0)) < 0) { if (errno == EINTR) continue; return -1; } if (ret == 0) return 0; *fd_to_recv = *(int*)CMSG_DATA((struct cmsghdr*)msg.msg_control); return *fd_to_recv; } //執(zhí)行close //fd 描述符 void Close(int fd) { while (close(fd) < 0) { if (errno == EINTR) continue; printErrExit("Close error"); } } //執(zhí)行accept //skfd 描述符 //addr struct sockaddr結構 //addrlen addr的大小 //ret 返回值 void Accept(int skfd, SA *addr, socklen_t *addrlen, int *ret) { int clifd; if (ret == NULL) printErrExit("Accept error"); while ((clifd = accept(skfd, addr, addrlen)) < 0) { if (errno == EINTR) continue; printErrExit("Accept error"); } *ret = clifd; } //初始化struct sockaddr_in結構 //stru 指向要初始化的struct sockaddr_in結構的指針 //protoc 地址族 //addr ip地址,可以是INADDR_ANY //port 端口 //返回值:成功返回0,出錯返回-1 //注意:不對protoc(地址族)參數進行檢查 int init_sockaddr(struct sockaddr_in *stru, int protoc, const char *addr, unsigned int port) { if (stru == NULL || addr == NULL) return -1; if (port > 65535) return -1; memset(stru, 0, sizeof(struct sockaddr_in)); if (strcmp(addr, "INADDR_ANY") == 0) (stru->sin_addr).s_addr = htonl(INADDR_ANY); else { if (inet_addr(addr) == INADDR_NONE) return -1; (stru->sin_addr).s_addr = inet_addr(addr); } stru->sin_family = protoc; stru->sin_port = htons(port); return 0; } void Init_sockaddr(struct sockaddr_in *stru, int protoc, const char *addr, unsigned int port) { if (stru == NULL || addr == NULL) printErrExit("Init_sockaddr error"); if (port > 65535) printErrExit("Init_sockaddr error"); memset(stru, 0, sizeof(struct sockaddr_in)); if (strcmp(addr, "INADDR_ANY") == 0) (stru->sin_addr).s_addr = htonl(INADDR_ANY); else { if (inet_addr(addr) == INADDR_NONE) printErrExit("Init_sockaddr error"); (stru->sin_addr).s_addr = inet_addr(addr); } stru->sin_family = protoc; stru->sin_port = htons(port); } //建立一個TCP套接字并連接到指定ip地址和指定端口(阻塞版本,connect會一直阻塞,直到到達默認超時時間) //addr ip地址 //port 端口 //返回值:連接成功返回描述符,出錯返回-1 int tcp_connect(const char *addr, unsigned int port) { int skfd; struct sockaddr_in saddr; if( (init_sockaddr(&saddr, AF_INET, addr, port)) < 0) return -1; if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; while (connect(skfd, (SA*)&saddr, sizeof(saddr)) < 0) { if (errno == EINTR) continue; else { close(skfd); return -1; } } return skfd; } void Tcp_connect(const char *addr, unsigned int port, int *ret) { int skfd; struct sockaddr_in saddr; if (ret == NULL) printErrExit("Tcp_connect error"); if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) printErrExit("Tcp_connect error"); if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) printErrExit("Tcp_connect error"); while (connect(skfd, (SA*)&saddr, sizeof(saddr)) < 0) { if (errno == EINTR) continue; else { close(skfd); printErrExit("Tcp_connect error"); } } *ret = skfd; } //建立一個套接字,并且綁定,監(jiān)聽 //addr 要綁定的ip地址 INADDR_ANY或ipv4地址 //port 要監(jiān)聽的端口 //backlog listen函數的監(jiān)聽排隊數 //返回值:成功返回套接字描述符,出錯返回-1 int tcp_listen(const char *addr, unsigned int port, int backlog) { int skfd; struct sockaddr_in saddr; if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) return -1; if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1; if (bind(skfd, (SA*)&saddr, sizeof(saddr)) < 0) { close(skfd); return -1; } if (listen(skfd, backlog) < 0) { close(skfd); return -1; } return skfd; } void Tcp_listen(const char *addr, unsigned int port, int backlog, int *ret) { int skfd; struct sockaddr_in saddr; if (ret == NULL) printErrExit("Tcp_listen error"); if (init_sockaddr(&saddr, AF_INET, addr, port) < 0) printErrExit("Tcp_listen error"); if ( (skfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) printErrExit("Tcp_listen error"); if (bind(skfd, (SA*)&saddr, sizeof(saddr)) < 0) { close(skfd); printErrExit("Tcp_listen error"); } if (listen(skfd, backlog) < 0) { close(skfd); printErrExit("Tcp_listen error"); } *ret = skfd; } //發(fā)送n個字節(jié) //fd 描述符 //vptr指向要發(fā)送的數據 //n 要發(fā)送的字節(jié)數 //出錯返回-1,否則返回發(fā)送的字節(jié)數 ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft = n; ssize_t nwritten; const char *ptr = (const char*)vptr; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0 ) { if (nwritten < 0 && errno == EINTR) nwritten = 0; else return (-1); } nleft -= nwritten; ptr += nwritten; } return (n); } //讀取指定的字節(jié)數 //fd 描述符 //ptr 指向存放數據的指針 //n 要接收的字節(jié)數 //對端關閉返回0,出錯返回-1,否則返回接收的字節(jié)數 ssize_t readn(int fd, void *vptr, size_t n) { char c; int ret; char *ptr = (char*)vptr; size_t i; ssize_t size = 0; if (vptr == NULL) return -1; for(i=0; i<n; i++) { ret = read(fd, &c, 1); if (ret == 0) return 0; else if (ret < 0 && errno == EINTR) i--; else if (ret == 1) ptr[i] = c; else return -1; } return n; } //發(fā)送指定的字節(jié)數的數據 //skfd 套接字描述符 //sendbuf 要發(fā)送的字符串 //size 要發(fā)送的字節(jié)數 //出錯返回-1,否則返回發(fā)送的字節(jié)數 ssize_t sendAll(int skfd, const void* sendBuf, size_t size) { const char *ptr = (const char*)sendBuf; if (sendBuf == NULL) return -1; if (writen(skfd, &size, sizeof(size)) == sizeof(size)) { if (writen(skfd, ptr, size) == size) return size; else return -1; } return -1; } //接收指定字節(jié)數的數據 //skfd 描述符 //recvbuf 存放接收數據 //size 要接收的數據大小 //返回接收的字節(jié)數 //出錯返回-1, 對端關閉返回0, 否則返回接收的字節(jié)數 ssize_t recvAll(int skfd, void **recvPtr) { size_t len; ssize_t ret; ret = readn(skfd, &len, sizeof(len)); if (ret == 0) return 0; if (ret < 0) return -1; freePtr(*recvPtr); *recvPtr = Malloc(len + 1); ret = readn(skfd, *recvPtr, len); if (ret == 0) { freePtr(*recvPtr); return 0; } if (ret < 0) { freePtr(*recvPtr); return -1; } return ret; } void Pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) { if (pthread_create(thread, attr, start_routine, arg) != 0) printErrExit("Pthread_create error"); } #endif







生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 一区二区在线视频免费观看 | 欧美日韩加勒比一区二区三区 | 九九精品免费观看在线 | 中文精品久久久久国产不卡 | 欧美日韩精品国产一区二区 | 香蕉乱码成人久久天堂爱免费 | 亚洲国产第一 | 国内精品视频成人一区二区 | 中文字幕巨大乳在线看 | 欧美最爽乱淫视频播放黑人 | 国产免费看网站v片不遮挡 国产免费全部免费观看 | 中文字幕片 | 欧美人与禽xoxo性伦交 | 毛片资源站 | 日本不卡视频一区二区三区 | 国产精品视频分类一区 | 亚洲国产精品久久综合 | 波多野一区二区三区在线 | 国产三区视频 | 午夜dj视频在线高清免费 | 三级黄视频 | 九九久久久2 | 欧美亚洲国产精品久久 | 日本免费新一区二区三区 | 免费一级毛片免费播放 | 国产在线高清不卡免费播放 | 国产呦精品一区二区三区网站 | 人成午夜视频 | 国内精品久久影视 | 大杳蕉伊人狼人久久一本线 | 国产精品αv在线观看 | 亚洲地址一地址二地址三 | 午夜大片免费男女爽爽影院久久 | 免费一级毛片在线观看 | 欧美精品 在线观看 | 午夜视频啪啪 | 日韩淫片| 精品视频一区二区三区在线观看 | 中文字幕视频免费在线观看 | 好大好爽快点吃奶 | 免费视频网站一级人爱视频 |