生产者消费者模型如下:
程序如下:
1 #include <unistd.h> 2 #include <sys/types.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <errno.h> 7 #include <string.h> 8 9 #include <pthread.h> 10 11 int g_Count = 0; 12 13 int nNum, nLoop; 14 15 //定义锁 16 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 17 18 //定义条件并初始化 19 pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER; 20 21 #define CUSTOM_COUNT 2 22 #define PRODUCT_COUNT 4 23 24 25 // int pthread_mutex_lock(pthread_mutex_t *mutex); 26 // int pthread_mutex_trylock(pthread_mutex_t *mutex); 27 // int pthread_mutex_unlock(pthread_mutex_t *mutex); 28 29 /* 30 int pthread_cond_timedwait(pthread_cond_t *restrict cond, 31 pthread_mutex_t *restrict mutex, 32 const struct timespec *restrict abstime); 33 int pthread_cond_wait(pthread_cond_t *restrict cond, 34 pthread_mutex_t *restrict mutex); 35 */ 36 37 //posix 线程库的函数 线程库 38 void *consume(void* arg) 39 { 40 41 int inum = 0; 42 inum = (int)arg; 43 while(1) 44 { 45 pthread_mutex_lock(&mutex); 46 printf("consum:%d\n", inum); 47 while (g_Count == 0) //while 醒来以后需要重新判断 条件g_Count是否满足,如果不满足,再次wait 48 { 49 printf("consum:%d 开始等待\n", inum); 50 pthread_cond_wait(&my_condition, &mutex); //api做了三件事情 //pthread_cond_wait假醒 51 printf("consum:%d 醒来\n", inum); 52 } 53 54 printf("consum:%d 消费产品begin\n", inum); 55 g_Count--; //消费产品 56 printf("consum:%d 消费产品end\n", inum); 57 58 pthread_mutex_unlock(&mutex); 59 60 sleep(1); 61 } 62 63 pthread_exit(0); 64 65 } 66 67 //生产者线程 68 // 69 void *produce(void* arg) 70 { 71 int inum = 0; 72 inum = (int)arg; 73 74 while(1) 75 { 76 77 /* 78 //因为是很多生产者调用produce,要保护全局变量g_Count,所以加锁 79 pthread_mutex_lock(&mutex); 80 if (g_Count > 20) 81 { 82 printf("produce:%d 产品太多,需要控制,休眠\n", inum); 83 pthread_mutex_unlock(&mutex); 84 sleep(1); 85 continue; 86 } 87 else 88 { 89 pthread_mutex_unlock(&mutex); 90 } 91 */ 92 93 pthread_mutex_lock(&mutex); 94 printf("产品数量:%d\n", g_Count); 95 printf("produce:%d 生产产品begin\n", inum); 96 g_Count++; 97 //只要我生产出一个产品,就告诉消费者去消费 98 printf("produce:%d 生产产品end\n", inum); 99 100 printf("produce:%d 发条件signal begin\n", inum); 101 pthread_cond_signal(&my_condition); //通知,在条件上等待的线程 102 printf("produce:%d 发条件signal end\n", inum); 103 104 pthread_mutex_unlock(&mutex); 105 sleep(1); 106 } 107 108 pthread_exit(0); 109 110 } 111 112 //结论:return arg 和 pthread_exit()的结果都可以让pthread_join 接过来 113 int main() 114 { 115 int i =0; 116 pthread_t tidArray[CUSTOM_COUNT+PRODUCT_COUNT+10]; 117 118 //创建消费者线程 119 for (i=0; i<CUSTOM_COUNT; i++) 120 { 121 pthread_create(&tidArray[i], NULL, consume, (void *)i); 122 } 123 124 sleep(1); 125 //创建生产线程 126 for (i=0; i<PRODUCT_COUNT; i++) 127 { 128 pthread_create(&tidArray[i+CUSTOM_COUNT], NULL, produce, (void*)i); 129 } 130 131 132 133 for (i=0; i<CUSTOM_COUNT+PRODUCT_COUNT; i++) 134 { 135 pthread_join(tidArray[i], NULL); //等待线程结束。。。 136 } 137 138 139 printf("进程也要结束1233\n"); 140 141 return 0; 142 }
执行结果如下:
条件等待模型如下:
多线程访问共享内存,通过信号量同步:不同进程中的线程无法进行同步与互斥
1 #include <sys/types.h> 2 #include <unistd.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <signal.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <sys/wait.h> 12 13 #include "myipc_sem.h" 14 #include "myipc_shm.h" 15 16 #include <pthread.h> 17 18 int g_key = 0x3333; 19 20 void TestFunc(int loopnum) 21 { 22 printf("loopnum:%d\n", loopnum); 23 24 int ncount = 0; 25 int ret = 0; 26 int shmhdl = 0; 27 int *addr = NULL; 28 29 int semid = 0; 30 sem_open(g_key, &semid); 31 32 33 sem_p(semid); //临界区开始 34 // 35 ret = IPC_CreatShm(".", 0, &shmhdl); 36 37 ret =IPC_MapShm(shmhdl, (void **)&addr); 38 *((int *)addr) = *((int *)addr) + 1; 39 ncount = *((int *)addr); 40 printf("ncount:%d\n", ncount); 41 //addr[0] = addr[0] +1; 42 ret =IPC_UnMapShm(addr); 43 //sleep(2); 44 45 sem_v(semid); //临界区开始 46 // 47 printf("进程正常退出:%d\n", getpid()); 48 } 49 50 51 52 //posix 线程库的函数 线程库 53 void *thread_routine(void* arg) 54 { 55 printf("thread_routine start\n"); 56 TestFunc(1); 57 pthread_exit(0); 58 59 } 60 61 int main(void ) 62 { 63 int res; 64 int procnum=10; 65 int loopnum = 100; 66 67 pthread_t tidArray[200]; 68 69 70 int i=0,j = 0; 71 72 printf("请输入要创建子进程的个数 : \n"); 73 scanf("%d", &procnum); 74 75 printf("请输入让每个子进程测试多少次 :\n"); 76 scanf("%d", &loopnum); 77 78 //共享内存创建 79 int ret = 0; 80 int shmhdl = 0; 81 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 82 if (ret != 0) 83 { 84 printf("func IPC_CreatShm() err:%d \n", ret); 85 return ret; 86 } 87 88 89 //信号量的创建 90 int semid = 0; 91 ret = sem_creat(g_key, &semid); 92 if (ret != 0) 93 { 94 printf("func sem_creat() err:%d,重新按照open打开信号量 \n", ret); 95 if (ret == SEMERR_EEXIST) 96 { 97 ret = sem_open(g_key, &semid); 98 if (ret != 0) 99 { 100 printf("按照打开的方式,重新获取sem失败:%d \n", ret); 101 return ret; 102 } 103 } 104 else 105 { 106 return ret; 107 } 108 109 } 110 111 int val = 0; 112 ret = sem_getval(semid, &val); 113 if (ret != 0 ) 114 { 115 printf("func sem_getval() err:%d \n", ret); 116 return ret; 117 } 118 printf("sem val:%d\n", val); 119 getchar(); 120 121 for (i=0; i<procnum; i++) 122 { 123 124 //tmp.numId = i; //这说明 线程函数在使用了一个不断变化的内存空间。。。。 125 pthread_create(&tidArray[i], NULL, thread_routine, NULL); 126 } 127 128 for (i=0; i<procnum; i++) 129 { 130 pthread_join(tidArray[i], NULL); //等待线程结束。。。 131 } 132 133 134 printf("父进程退出 hello...\n"); 135 return 0; 136 }
多线程访问共享内存,通过线程锁实现:
1 #include <sys/types.h> 2 #include <unistd.h> 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #include <signal.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <sys/wait.h> 12 13 #include "myipc_sem.h" 14 #include "myipc_shm.h" 15 16 #include <pthread.h> 17 18 pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; 19 20 int g_key = 0x3333; 21 22 void TestFunc(int loopnum) 23 { 24 printf("loopnum:%d\n", loopnum); 25 26 int ncount = 0; 27 int ret = 0; 28 int shmhdl = 0; 29 int *addr = NULL; 30 31 int semid = 0; 32 sem_open(g_key, &semid); 33 34 35 sem_p(semid); //临界区开始 36 // 37 ret = IPC_CreatShm(".", 0, &shmhdl); 38 39 ret =IPC_MapShm(shmhdl, (void **)&addr); 40 *((int *)addr) = *((int *)addr) + 1; 41 ncount = *((int *)addr); 42 printf("ncount:%d\n", ncount); 43 //addr[0] = addr[0] +1; 44 ret =IPC_UnMapShm(addr); 45 //sleep(2); 46 47 sem_v(semid); //临界区开始 48 // 49 printf("进程正常退出:%d\n", getpid()); 50 } 51 52 void TestFunc_threadMutex(int loopnum) 53 { 54 printf("loopnum:%d\n", loopnum); 55 56 int ncount = 0; 57 int ret = 0; 58 int shmhdl = 0; 59 int *addr = NULL; 60 61 int semid = 0; 62 sem_open(g_key, &semid); 63 64 65 //sem_p(semid); //临界区开始 66 pthread_mutex_lock(&mymutex); 67 // 68 ret = IPC_CreatShm(".", 0, &shmhdl); 69 70 ret =IPC_MapShm(shmhdl, (void **)&addr); 71 *((int *)addr) = *((int *)addr) + 1; 72 ncount = *((int *)addr); 73 printf("ncount:%d\n", ncount); 74 //addr[0] = addr[0] +1; 75 ret =IPC_UnMapShm(addr); 76 //sleep(2); 77 78 //sem_v(semid); //临界区开始 79 pthread_mutex_unlock(&mymutex); 80 // 81 printf("进程正常退出:%d\n", getpid()); 82 } 83 84 85 86 87 //posix 线程库的函数 线程库 88 void *thread_routine(void* arg) 89 { 90 printf("thread_routine start\n"); 91 //TestFunc(1); 92 TestFunc_threadMutex(1); 93 pthread_exit(0); 94 95 } 96 97 int main(void ) 98 { 99 int res; 100 int procnum=10; 101 int loopnum = 100; 102 103 pthread_t tidArray[1024*10]; 104 105 106 int i=0,j = 0; 107 108 printf("请输入要创建子进程的个数 : \n"); 109 scanf("%d", &procnum); 110 111 printf("请输入让每个子进程测试多少次 :\n"); 112 scanf("%d", &loopnum); 113 114 //共享内存创建 115 int ret = 0; 116 int shmhdl = 0; 117 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 118 if (ret != 0) 119 { 120 printf("func IPC_CreatShm() err:%d \n", ret); 121 return ret; 122 } 123 124 125 //信号量的创建 126 int semid = 0; 127 ret = sem_creat(g_key, &semid); 128 if (ret != 0) 129 { 130 printf("func sem_creat() err:%d,重新按照open打开信号量 \n", ret); 131 if (ret == SEMERR_EEXIST) 132 { 133 ret = sem_open(g_key, &semid); 134 if (ret != 0) 135 { 136 printf("按照打开的方式,重新获取sem失败:%d \n", ret); 137 return ret; 138 } 139 } 140 else 141 { 142 return ret; 143 } 144 145 } 146 147 int val = 0; 148 ret = sem_getval(semid, &val); 149 if (ret != 0 ) 150 { 151 printf("func sem_getval() err:%d \n", ret); 152 return ret; 153 } 154 printf("sem val:%d\n", val); 155 getchar(); 156 157 for (i=0; i<procnum; i++) 158 { 159 160 //tmp.numId = i; //这说明 线程函数在使用了一个不断变化的内存空间。。。。 161 pthread_create(&tidArray[i], NULL, thread_routine, NULL); 162 } 163 164 for (i=0; i<procnum; i++) 165 { 166 pthread_join(tidArray[i], NULL); //等待线程结束。。。 167 } 168 169 170 printf("父进程退出 hello...\n"); 171 return 0; 172 }
服务器多进程模型、共享内存、信号量:
信号量封装:
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <fcntl.h> 5 #include <sys/mman.h> 6 #include <sys/ipc.h> 7 #include <sys/shm.h> 8 #include <sys/sem.h> 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include <sys/ipc.h> 16 #include <sys/sem.h> 17 #include "myipc_sem.h" 18 19 20 union semun { 21 int val; /* Value for SETVAL */ 22 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 23 unsigned short *array; /* Array for GETALL, SETALL */ 24 struct seminfo *__buf; /* Buffer for IPC_INFO 25 (Linux specific) */ 26 }; 27 28 //@返回值 0 正确 其他错误 29 int sem_creat(int key, int *semid) 30 { 31 int ret = 0; 32 //int tmpsemid = 0; 33 34 if (semid == NULL) 35 { 36 ret = SEMERR_PARAM; 37 printf("func sem_creat() err:%d\n", ret); 38 return ret; 39 } 40 ret = semget(key, 1, 0666| IPC_CREAT | IPC_EXCL); 41 if (ret == -1) 42 { 43 ret = errno; 44 //perror("semget"); 45 if (errno == EEXIST) 46 { 47 ret = SEMERR_EEXIST; 48 printf("func sem_creat() 检测到信号量集已经存在:%d\n", ret); 49 return ret; 50 } 51 } 52 *semid = ret; 53 54 ret = sem_setval(*semid, 1); 55 if (ret != 0) 56 { 57 printf("func sem_setval() err:%d\n", ret); 58 return ret; 59 } 60 ret = 0; 61 return ret; 62 } 63 64 int sem_open(int key, int *semid) 65 { 66 int ret = 0; 67 68 if (semid == NULL) 69 { 70 ret = SEMERR_PARAM; 71 printf("func sem_open() err:%d\n", ret); 72 return ret; 73 } 74 75 ret = semget(key, 0, 0); 76 if (ret == -1) 77 { 78 ret = errno; 79 printf("func sem_open() 失败:%d\n", ret); 80 return ret; 81 } 82 *semid = ret; 83 ret = 0; 84 return ret; 85 } 86 87 int sem_setval(int semid, int val) 88 { 89 int ret = 0; 90 union semun su; 91 su.val = val; 92 ret = semctl(semid, 0, SETVAL, su); 93 return ret; 94 } 95 96 /* 97 int sem_getval(int semid, int *val) 98 { 99 int ret = 0; 100 int tmpval; 101 if (val == NULL) 102 { 103 ret = SEMERR_PARAM; 104 printf("func sem_getval() err:%d\n", ret); 105 return ret; 106 } 107 union semun su; 108 tmpval = su.val ; 109 ret = semctl(semid, 0, GETVAL, su); 110 *val = tmpval ; 111 printf("val:%d\n", tmpval); 112 return ret; 113 } 114 */ 115 int sem_getval(int semid, int *myval) 116 { 117 int ret = 0; 118 int val; 119 union semun su; 120 val = su.val ; 121 //信号量 计数值 122 ret = semctl(semid, 0, GETVAL, su); 123 //printf("val:%d\n", val); 124 125 *myval = ret; 126 ret = 0; 127 return ret; 128 } 129 130 //信号量p操作时候,需要传递好几个信息给linux内核 131 //所以linux内核定义了一个结构 132 //我要操作信号量集的下标 0 133 //我要执行什么操作 -1 +1 134 //我按照什么策略执行操作 0 UNDO NOWAITing 135 int sem_p(int semid) 136 { 137 struct sembuf buf = {0, -1, 0}; 138 int ret = 0; 139 ret = semop(semid, &buf, 1); 140 return ret; 141 } 142 143 int sem_v(int semid) 144 { 145 struct sembuf buf = {0, 1, 0}; 146 int ret = 0; 147 ret = semop(semid, &buf, 1); 148 return ret; 149 } 150 151 152 /* 153 int main() 154 { 155 156 //IPC_CREAT and IPC_EXCL a 157 int semid; 158 semid = sem_creat(0x1111); 159 //sem_setval(semid, 1); 160 //sem_getval(semid); 161 162 163 int pid = 0; 164 pid = fork(); 165 166 167 //sem_p(semid); 168 int i=0; 169 // printf("i:%d pid:%d \n", i++, getpid()); 170 // sleep(3); 171 // printf("i:%d pid:%d \n", i++, getpid()); 172 173 //sem_v(semid); 174 175 176 177 return 0; 178 } 179 */
共享内存封装:
1 #define _OS_LINUX_ 2 3 #if defined _OS_LINUX_ 4 #include <stdio.h> 5 #include <errno.h> 6 #include <unistd.h> 7 #include <memory.h> 8 #include <sys/ipc.h> 9 #include <sys/shm.h> 10 #include <sys/sem.h> 11 #include <sys/msg.h> 12 #include "myipc_shm.h" 13 14 #endif 15 16 int shmflag = 0; 17 int shmkey; 18 19 /*********************************************************************** 20 功能描述: 创建共享内存 21 参数说明: shmname [in] 是共享内存名,系统中唯一标志 22 shmsize [in] 是要创建的共享内存的大小; 23 shmhdl [out] 共享内存的句柄. 24 返回值: 返回0函数执行成功;非0返回错误码 25 ************************************************************************/ 26 int IPC_CreatShm(char *shmseedfile, int shmsize, int *shmhdl) 27 { 28 if(shmflag == 0) //判断接口中共享内存key是否已经存在 29 { 30 shmkey = ftok(shmseedfile, 'c'); 31 if (shmkey == -1) 32 { 33 perror("ftok"); 34 return -1; 35 } 36 37 shmflag = 1; 38 } 39 40 //创建共享内存 41 *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666); 42 if (*shmhdl == -1) //创建失败 43 return -2; 44 return 0; 45 46 } 47 /*********************************************************************** 48 功能描述: 关联共享内存 49 参数说明: shmhdl [in] 共享的句柄 50 mapaddr [out] 共享内存首地址 51 返回值: 返回0函数执行成功;非0返回错误码 52 ************************************************************************/ 53 int 54 IPC_MapShm(int shmhdl, void **mapaddr) 55 { 56 void *tempptr = NULL; 57 58 //连接共享内存 59 tempptr = (void *)shmat(shmhdl,0,SHM_RND); 60 if ((int)tempptr == -1) //共享内存连接失败 61 return -1; 62 *mapaddr = tempptr; //导出共享内存首指针 63 64 return 0; 65 } 66 /*********************************************************************** 67 功能描述: 取消共享内存关联 68 参数说明: unmapaddr [in] 共享内存首地址 69 返回值: 返回0函数执行成功;非0返回错误码 70 ************************************************************************/ 71 int IPC_UnMapShm(void *unmapaddr) 72 { 73 int rv; 74 //取消连接共享内存 75 rv = shmdt((char *)unmapaddr); 76 if (rv == -1) //取消连接失败 77 return -1; 78 79 return 0; 80 } 81 /*********************************************************************** 82 功能描述: 删除共享内存 83 参数说明: shmhdl [in] 共享的句柄 84 返回值: 返回0函数执行成功;非0返回错误码 85 ************************************************************************/ 86 int IPC_DelShm(int shmhdl) 87 { 88 int rv; 89 //删除共享内存 90 rv = shmctl(shmhdl,IPC_RMID,NULL); 91 if(rv < 0) //删除共享内存失败 92 return -1; 93 return 0; 94 }
客户端:
1 #include <unistd.h> 2 #include <sys/types.h> 3 //#include <sys/socket.h> 4 //#include <netinet/in.h> 5 //#include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 //#include "sckutil.h" 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include "commsocket.h" 16 17 void handle(int signum) 18 { 19 int pid = 0; 20 printf("recv signum:%d \n", signum); 21 22 //避免僵尸进程 23 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 24 { 25 printf("退出子进程pid%d \n", pid); 26 fflush(stdout); 27 } 28 } 29 30 31 32 int main() 33 { 34 int ret = 0; 35 void *handle = NULL; 36 //void handle = NULL; 37 int connfd; 38 int i = 0, j = 0; 39 40 signal(SIGCHLD, handle); 41 signal(SIGPIPE, SIG_IGN); //防止 sokcet破裂 42 43 int procnum=10; 44 int loopnum = 100; 45 46 pthread_t tidArray[1024*2]; 47 48 49 50 printf("请输入要创建子进程的个数 : \n"); 51 scanf("%d", &procnum); 52 53 printf("请输入让每个子进程测试多少次 :\n"); 54 scanf("%d", &loopnum); 55 56 57 unsigned char *data = (unsigned char *)"aaaaaafffffffffffssssss"; 58 int datalen = 10; 59 60 unsigned char out[1024]; 61 int outlen = 1024; 62 //客户端环境初始化 63 64 ret = sckCliet_init(&handle, 15, 5, 5, 10); 65 66 for (i=0; i<procnum; i++) 67 { 68 int pid = fork(); 69 if (pid == 0) 70 { 71 ret = sckCliet_getconn(handle, "127.0.0.1", 8001, &connfd); 72 for (j=0; j<loopnum; j++) 73 { 74 //客户端发送报文 75 ret = sckClient_send(handle, connfd, data, datalen); 76 if (ret != 0) 77 { 78 if (ret == Sck_ErrTimeOut) 79 { 80 continue; 81 } 82 break; 83 } 84 //printf("ccccccc\n"); 85 //客户端端接受报文 86 ret = sckClient_rev(handle, connfd, out, &outlen); //10 87 if (ret != 0) 88 { 89 if (ret == Sck_ErrTimeOut) 90 { 91 break; 92 } 93 break; 94 } 95 out[outlen] = '\0'; 96 97 printf("out: %s \n", out); 98 } 99 100 close(connfd); 101 exit(0); //让子进程退出,不参与fork 102 } 103 } 104 105 106 // 客户端环境释放 107 ret = sckClient_destroy(handle); 108 109 //避免僵尸进程 110 int mypid; 111 while ((mypid = waitpid(-1, NULL, WNOHANG) ) > 0) 112 { 113 printf("退出子进程pid%d \n", mypid); 114 fflush(stdout); 115 } 116 117 }
服务器:
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <signal.h> 4 #include <sys/wait.h> 5 6 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <errno.h> 10 #include <string.h> 11 #include "commsocket.h" 12 13 #include "myipc_sem.h" 14 #include "myipc_shm.h" 15 int g_key = 0x3333; 16 17 #define ERR_EXIT(m) \ 18 do \ 19 { \ 20 perror(m); \ 21 exit(EXIT_FAILURE); \ 22 } while(0) 23 24 25 #include <signal.h> 26 27 void handle(int signum) 28 { 29 int pid = 0; 30 printf("recv signum:%d \n", signum); 31 32 //避免僵尸进程 33 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 34 { 35 printf("退出子进程pid%d \n", pid); 36 fflush(stdout); 37 } 38 } 39 40 int srvInit() 41 { 42 //共享内存创建 43 int ret = 0; 44 int shmhdl = 0; 45 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 46 if (ret != 0) 47 { 48 printf("func IPC_CreatShm() err:%d \n", ret); 49 return ret; 50 } 51 52 53 //信号量的创建 54 int semid = 0; 55 ret = sem_creat(g_key, &semid); 56 if (ret != 0) 57 { 58 printf("func sem_creat() err:%d,重新按照open打开信号量 \n", ret); 59 if (ret == SEMERR_EEXIST) 60 { 61 ret = sem_open(g_key, &semid); 62 if (ret != 0) 63 { 64 printf("按照打开的方式,重新获取sem失败:%d \n", ret); 65 return ret; 66 } 67 } 68 else 69 { 70 return ret; 71 } 72 73 } 74 75 int val = 0; 76 ret = sem_getval(semid, &val); 77 if (ret != 0 ) 78 { 79 printf("func sem_getval() err:%d \n", ret); 80 return ret; 81 } 82 printf("sem val:%d\n", val); 83 84 } 85 86 87 void TestFunc() 88 { 89 int ncount = 0; 90 int ret = 0; 91 int shmhdl = 0; 92 int *addr = NULL; 93 94 int semid = 0; 95 sem_open(g_key, &semid); 96 97 98 sem_p(semid); //临界区开始 99 // 100 ret = IPC_CreatShm(".", 0, &shmhdl); 101 102 ret =IPC_MapShm(shmhdl, (void **)&addr); 103 *((int *)addr) = *((int *)addr) + 1; 104 ncount = *((int *)addr); 105 printf("ncount:%d\n", ncount); 106 //addr[0] = addr[0] +1; 107 ret =IPC_UnMapShm(addr); 108 //sleep(2); 109 110 sem_v(semid); //临界区开始 111 // 112 //printf("进程正常退出:%d\n", getpid()); 113 } 114 115 int main(void) 116 { 117 int ret = 0; 118 int listenfd; 119 120 121 signal(SIGCHLD, handle); 122 signal(SIGPIPE, SIG_IGN); 123 124 //完成共享内存和信号量的创建 125 srvInit(); 126 //getchar(); 127 128 ret = sckServer_init(8001, &listenfd); 129 if (ret != 0) 130 { 131 printf("sckServer_init() err:%d \n", ret); 132 return ret; 133 } 134 135 while(1) 136 { 137 int ret = 0; 138 int wait_seconds = 5; 139 int connfd = 0; 140 141 ret = sckServer_accept(listenfd, &connfd, wait_seconds); 142 if (ret == Sck_ErrTimeOut) 143 { 144 //printf("timeout....\n"); 145 continue; 146 } 147 148 int pid = fork(); 149 if (pid == 0) 150 { 151 unsigned char recvbuf[1024]; 152 int recvbuflen = 1024; 153 154 close(listenfd); 155 while(1) 156 { 157 memset(recvbuf, 0, sizeof(recvbuf)); 158 ret = sckServer_rev(connfd, recvbuf, &recvbuflen, wait_seconds); 159 if (ret != 0) 160 { 161 printf("func sckServer_rev() err:%d \n", ret); 162 break; 163 } 164 165 TestFunc(); 166 printf("recvbuf:%s\n", recvbuf); 167 168 // 169 ret = sckServer_send(connfd, recvbuf, recvbuflen, wait_seconds); 170 if (ret != 0) 171 { 172 printf("func sckServer_send() err:%d \n", ret); 173 break; 174 } 175 } 176 close(connfd); 177 exit(ret); 178 } 179 else if (pid > 0) 180 { 181 close(connfd); 182 } 183 } 184 185 186 return 0; 187 }
服务器多线程框架:
客户端连接封装:
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 9 #include <fcntl.h> 10 11 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <errno.h> 15 #include <string.h> 16 17 #include "commsocket.h" 18 19 typedef struct _SckHandle 20 { 21 int sockArray[100]; 22 int arrayNum; 23 int sockfd; 24 int contime; 25 int sendtime; 26 int revtime; 27 28 }SckHandle; 29 30 /** 31 * readn - 读取固定字节数 32 * @fd: 文件描述符 33 * @buf: 接收缓冲区 34 * @count: 要读取的字节数 35 * 成功返回count,失败返回-1,读到EOF返回<count 36 */ 37 ssize_t readn(int fd, void *buf, size_t count) 38 { 39 size_t nleft = count; 40 ssize_t nread; 41 char *bufp = (char*)buf; 42 43 while (nleft > 0) 44 { 45 if ((nread = read(fd, bufp, nleft)) < 0) 46 { 47 if (errno == EINTR) 48 continue; 49 return -1; 50 } 51 else if (nread == 0) 52 return count - nleft; 53 54 bufp += nread; 55 nleft -= nread; 56 } 57 58 return count; 59 } 60 61 /** 62 * writen - 发送固定字节数 63 * @fd: 文件描述符 64 * @buf: 发送缓冲区 65 * @count: 要读取的字节数 66 * 成功返回count,失败返回-1 67 */ 68 ssize_t writen(int fd, const void *buf, size_t count) 69 { 70 size_t nleft = count; 71 ssize_t nwritten; 72 char *bufp = (char*)buf; 73 74 while (nleft > 0) 75 { 76 if ((nwritten = write(fd, bufp, nleft)) < 0) 77 { 78 if (errno == EINTR) 79 continue; 80 return -1; 81 } 82 else if (nwritten == 0) 83 continue; 84 85 bufp += nwritten; 86 nleft -= nwritten; 87 } 88 89 return count; 90 } 91 92 /** 93 * recv_peek - 仅仅查看套接字缓冲区数据,但不移除数据 94 * @sockfd: 套接字 95 * @buf: 接收缓冲区 96 * @len: 长度 97 * 成功返回>=0,失败返回-1 98 */ 99 ssize_t recv_peek(int sockfd, void *buf, size_t len) 100 { 101 while (1) 102 { 103 int ret = recv(sockfd, buf, len, MSG_PEEK); 104 if (ret == -1 && errno == EINTR) 105 continue; 106 return ret; 107 } 108 } 109 110 111 //函数声明 112 //客户端环境初始化 113 int sckCliet_init(void **handle, int contime, int sendtime, int revtime, int nConNum) 114 { 115 int ret = 0; 116 if (handle == NULL ||contime<0 || sendtime<0 || revtime<0) 117 { 118 ret = Sck_ErrParam; 119 printf("func sckCliet_init() err: %d, check (handle == NULL ||contime<0 || sendtime<0 || revtime<0)\n", ret); 120 return ret; 121 } 122 123 SckHandle *tmp = (SckHandle *)malloc(sizeof(SckHandle)); 124 if (tmp == NULL) 125 { 126 ret = Sck_ErrMalloc; 127 printf("func sckCliet_init() err: malloc %d\n", ret); 128 return ret; 129 } 130 131 tmp->contime = contime; 132 tmp->sendtime = sendtime; 133 tmp->revtime = revtime; 134 tmp->arrayNum = nConNum; 135 136 137 /* 138 int sockfd; 139 int i = 0; 140 for (i=0; i<1; i++) 141 { 142 //链表的顺序 143 sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 144 if (sockfd < 0) 145 { 146 ret = errno; 147 printf("func socket() err: %d\n", ret); 148 return ret; 149 } 150 tmp->sockfd = sockfd; 151 } 152 */ 153 154 *handle = tmp; 155 return ret; 156 } 157 158 /** 159 * activate_noblock - 设置I/O为非阻塞模式 160 * @fd: 文件描符符 161 */ 162 int activate_nonblock(int fd) 163 { 164 int ret = 0; 165 int flags = fcntl(fd, F_GETFL); 166 if (flags == -1) 167 { 168 ret = flags; 169 printf("func activate_nonblock() err:%d", ret); 170 return ret; 171 } 172 173 174 flags |= O_NONBLOCK; 175 ret = fcntl(fd, F_SETFL, flags); 176 if (ret == -1) 177 { 178 printf("func activate_nonblock() err:%d", ret); 179 return ret; 180 } 181 return ret; 182 } 183 184 /** 185 * deactivate_nonblock - 设置I/O为阻塞模式 186 * @fd: 文件描符符 187 */ 188 int deactivate_nonblock(int fd) 189 { 190 int ret = 0; 191 int flags = fcntl(fd, F_GETFL); 192 if (flags == -1) 193 { 194 ret = flags; 195 printf("func deactivate_nonblock() err:%d", ret); 196 return ret; 197 } 198 199 flags &= ~O_NONBLOCK; 200 ret = fcntl(fd, F_SETFL, flags); 201 if (ret == -1) 202 { 203 printf("func deactivate_nonblock() err:%d", ret); 204 return ret; 205 } 206 return ret; 207 } 208 209 210 211 /** 212 * connect_timeout - connect 213 * @fd: 套接字 214 * @addr: 要连接的对方地址 215 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 216 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT 217 */ 218 static int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) 219 { 220 int ret; 221 socklen_t addrlen = sizeof(struct sockaddr_in); 222 223 if (wait_seconds > 0) 224 activate_nonblock(fd); 225 226 ret = connect(fd, (struct sockaddr*)addr, addrlen); 227 if (ret < 0 && errno == EINPROGRESS) 228 { 229 //printf("11111111111111111111\n"); 230 fd_set connect_fdset; 231 struct timeval timeout; 232 FD_ZERO(&connect_fdset); 233 FD_SET(fd, &connect_fdset); 234 timeout.tv_sec = wait_seconds; 235 timeout.tv_usec = 0; 236 do 237 { 238 // 一但连接建立,则套接字就可写 所以connect_fdset放在了写集合中 239 ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout); 240 } while (ret < 0 && errno == EINTR); 241 if (ret == 0) 242 { 243 ret = -1; 244 errno = ETIMEDOUT; 245 } 246 else if (ret < 0) 247 return -1; 248 else if (ret == 1) 249 { 250 //printf("22222222222222222\n"); 251 /* ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,*/ 252 /* 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 */ 253 int err; 254 socklen_t socklen = sizeof(err); 255 int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &socklen); 256 if (sockoptret == -1) 257 { 258 return -1; 259 } 260 if (err == 0) 261 { 262 //printf("3333333333333\n"); 263 ret = 0; 264 } 265 else 266 { 267 //printf("4444444444444444:%d\n", err); 268 errno = err; 269 ret = -1; 270 } 271 } 272 } 273 if (wait_seconds > 0) 274 { 275 deactivate_nonblock(fd); 276 } 277 return ret; 278 } 279 280 281 282 // 283 int sckCliet_getconn(void *handle, char *ip, int port, int *connfd) 284 { 285 286 int ret = 0; 287 SckHandle *tmp = NULL; 288 if (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537) 289 { 290 ret = Sck_ErrParam; 291 printf("func sckCliet_getconn() err: %d, check (handle == NULL || ip==NULL || connfd==NULL || port<0 || port>65537) \n", ret); 292 return ret; 293 } 294 295 // 296 int sockfd; 297 sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 298 if (sockfd < 0) 299 { 300 ret = errno; 301 printf("func socket() err: %d\n", ret); 302 return ret; 303 } 304 305 struct sockaddr_in servaddr; 306 memset(&servaddr, 0, sizeof(servaddr)); 307 servaddr.sin_family = AF_INET; 308 servaddr.sin_port = htons(port); 309 servaddr.sin_addr.s_addr = inet_addr(ip); 310 311 tmp = (SckHandle* )handle; 312 313 /* 314 ret = connect(sockfd, (struct sockaddr*) (&servaddr), sizeof(servaddr)); 315 if (ret < 0) 316 { 317 ret = errno; 318 printf("func connect() err: %d\n", ret); 319 return ret; 320 } 321 */ 322 323 ret = connect_timeout(sockfd, (struct sockaddr_in*) (&servaddr), (unsigned int )tmp->contime); 324 if (ret < 0) 325 { 326 if (ret==-1 && errno == ETIMEDOUT) 327 { 328 ret = Sck_ErrTimeOut; 329 return ret; 330 } 331 else 332 { 333 printf("func connect_timeout() err: %d\n", ret); 334 } 335 } 336 337 *connfd = sockfd; 338 339 return ret; 340 341 } 342 343 344 345 /** 346 * write_timeout - 写超时检测函数,不含写操作 347 * @fd: 文件描述符 348 * @wait_seconds: 等待超时秒数,如果为0表示不检测超时 349 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT 350 */ 351 int write_timeout(int fd, unsigned int wait_seconds) 352 { 353 int ret = 0; 354 if (wait_seconds > 0) 355 { 356 fd_set write_fdset; 357 struct timeval timeout; 358 359 FD_ZERO(&write_fdset); 360 FD_SET(fd, &write_fdset); 361 362 timeout.tv_sec = wait_seconds; 363 timeout.tv_usec = 0; 364 do 365 { 366 ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout); 367 } while (ret < 0 && errno == EINTR); 368 369 if (ret == 0) 370 { 371 ret = -1; 372 errno = ETIMEDOUT; 373 } 374 else if (ret == 1) 375 ret = 0; 376 } 377 378 return ret; 379 } 380 381 382 //客户端发送报文 383 int sckClient_send(void *handle, int connfd, unsigned char *data, int datalen) 384 { 385 int ret = 0; 386 387 SckHandle *tmp = NULL; 388 tmp = (SckHandle *)handle; 389 ret = write_timeout(connfd, tmp->sendtime); 390 if (ret == 0) 391 { 392 int writed = 0; 393 unsigned char *netdata = ( unsigned char *)malloc(datalen + 4); 394 if ( netdata == NULL) 395 { 396 ret = Sck_ErrMalloc; 397 printf("func sckClient_send() mlloc Err:%d\n ", ret); 398 return ret; 399 } 400 int netlen = htonl(datalen); 401 memcpy(netdata, &netlen, 4); 402 memcpy(netdata+4, data, datalen); 403 404 writed = writen(connfd, netdata, datalen + 4); 405 if (writed < (datalen + 4) ) 406 { 407 if (netdata != NULL) 408 { 409 free(netdata); 410 netdata = NULL; 411 } 412 return writed; 413 } 414 415 } 416 417 if (ret < 0) 418 { 419 //失败返回-1,超时返回-1并且errno = ETIMEDOUT 420 if (ret == -1 && errno == ETIMEDOUT) 421 { 422 ret = Sck_ErrTimeOut; 423 printf("func sckClient_send() mlloc Err:%d\n ", ret); 424 return ret; 425 } 426 return ret; 427 } 428 429 return ret; 430 } 431 432 433 434 /** 435 * read_timeout - 读超时检测函数,不含读操作 436 * @fd: 文件描述符 437 * @wait_seconds: 等待超时秒数,如果为0表示不检测超时 438 * 成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT 439 */ 440 int read_timeout(int fd, unsigned int wait_seconds) 441 { 442 int ret = 0; 443 if (wait_seconds > 0) 444 { 445 fd_set read_fdset; 446 struct timeval timeout; 447 448 FD_ZERO(&read_fdset); 449 FD_SET(fd, &read_fdset); 450 451 timeout.tv_sec = wait_seconds; 452 timeout.tv_usec = 0; 453 454 //select返回值三态 455 //1 若timeout时间到(超时),没有检测到读事件 ret返回=0 456 //2 若ret返回<0 && errno == EINTR 说明select的过程中被别的信号中断(可中断睡眠原理) 457 //2-1 若返回-1,select出错 458 //3 若ret返回值>0 表示有read事件发生,返回事件发生的个数 459 460 do 461 { 462 ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout); 463 } while (ret < 0 && errno == EINTR); 464 465 if (ret == 0) 466 { 467 ret = -1; 468 errno = ETIMEDOUT; 469 } 470 else if (ret == 1) 471 ret = 0; 472 } 473 474 return ret; 475 } 476 477 //客户端端接受报文 478 int sckClient_rev(void *handle, int connfd, unsigned char *out, int *outlen) 479 { 480 481 int ret = 0; 482 SckHandle *tmpHandle = (SckHandle *)handle; 483 484 if (handle==NULL || out==NULL) 485 { 486 ret = Sck_ErrParam; 487 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 488 return ret; 489 } 490 491 ret = read_timeout(connfd, tmpHandle->revtime ); //bugs modify bombing 492 if (ret != 0) 493 { 494 if (ret==-1 || errno == ETIMEDOUT) 495 { 496 ret = Sck_ErrTimeOut; 497 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 498 return ret; 499 } 500 else 501 { 502 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 503 return ret; 504 } 505 } 506 507 int netdatalen = 0; 508 ret = readn(connfd, &netdatalen, 4); //读包头 4个字节 509 if (ret == -1) 510 { 511 printf("func readn() err:%d \n", ret); 512 return ret; 513 } 514 else if (ret < 4) 515 { 516 ret = Sck_ErrPeerClosed; 517 printf("func readn() err peer closed:%d \n", ret); 518 return ret; 519 } 520 521 int n; 522 n = ntohl(netdatalen); 523 ret = readn(connfd, out, n); //根据长度读数据 524 if (ret == -1) 525 { 526 printf("func readn() err:%d \n", ret); 527 return ret; 528 } 529 else if (ret < n) 530 { 531 ret = Sck_ErrPeerClosed; 532 printf("func readn() err peer closed:%d \n", ret); 533 return ret; 534 } 535 536 *outlen = n; 537 538 return 0; 539 } 540 541 // 客户端环境释放 542 int sckClient_destroy(void *handle) 543 { 544 if (handle != NULL) 545 { 546 free(handle); 547 } 548 return 0; 549 } 550 551 int sckCliet_closeconn(int connfd) 552 { 553 if (connfd >=0 ) 554 { 555 close(connfd); 556 } 557 return 0; 558 } 559 560 561 562 / 563 //函数声明 564 //服务器端初始化 565 int sckServer_init(int port, int *listenfd) 566 { 567 int ret = 0; 568 int mylistenfd; 569 struct sockaddr_in servaddr; 570 memset(&servaddr, 0, sizeof(servaddr)); 571 servaddr.sin_family = AF_INET; 572 servaddr.sin_port = htons(port); 573 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 574 575 576 mylistenfd = socket(PF_INET, SOCK_STREAM, 0); 577 if (mylistenfd < 0) 578 { 579 ret = errno ; 580 printf("func socket() err:%d \n", ret); 581 return ret; 582 } 583 584 585 int on = 1; 586 ret = setsockopt(mylistenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ); 587 if (ret < 0) 588 { 589 ret = errno ; 590 printf("func setsockopt() err:%d \n", ret); 591 return ret; 592 } 593 594 595 ret = bind(mylistenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); 596 if (ret < 0) 597 { 598 ret = errno ; 599 printf("func bind() err:%d \n", ret); 600 return ret; 601 } 602 603 ret = listen(mylistenfd, SOMAXCONN); 604 if (ret < 0) 605 { 606 ret = errno ; 607 printf("func listen() err:%d \n", ret); 608 return ret; 609 } 610 611 *listenfd = mylistenfd; 612 613 return 0; 614 } 615 616 /** 617 * accept_timeout - 带超时的accept 618 * @fd: 套接字 619 * @addr: 输出参数,返回对方地址 620 * @wait_seconds: 等待超时秒数,如果为0表示正常模式 621 * 成功(未超时)返回已连接套接字,超时返回-1并且errno = ETIMEDOUT 622 */ 623 int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds) 624 { 625 int ret; 626 socklen_t addrlen = sizeof(struct sockaddr_in); 627 628 if (wait_seconds > 0) 629 { 630 fd_set accept_fdset; 631 struct timeval timeout; 632 FD_ZERO(&accept_fdset); 633 FD_SET(fd, &accept_fdset); 634 timeout.tv_sec = wait_seconds; 635 timeout.tv_usec = 0; 636 do 637 { 638 ret = select(fd + 1, &accept_fdset, NULL, NULL, &timeout); 639 } while (ret < 0 && errno == EINTR); 640 if (ret == -1) 641 return -1; 642 else if (ret == 0) 643 { 644 errno = ETIMEDOUT; 645 return -1; 646 } 647 } 648 649 //一但检测出 有select事件发生,表示对等方完成了三次握手,客户端有新连接建立 650 //此时再调用accept将不会堵塞 651 if (addr != NULL) 652 ret = accept(fd, (struct sockaddr*)addr, &addrlen); //返回已连接套接字 653 else 654 ret = accept(fd, NULL, NULL); 655 if (ret == -1) 656 { 657 ret = errno; 658 printf("func accept() err:%d \n", ret); 659 return ret; 660 } 661 662 663 return ret; 664 } 665 666 int sckServer_accept(int listenfd, int *connfd, int timeout) 667 { 668 int ret = 0; 669 670 ret = accept_timeout(listenfd, NULL, (unsigned int) timeout); 671 if (ret < 0) 672 { 673 if (ret == -1 && errno == ETIMEDOUT) 674 { 675 ret = Sck_ErrTimeOut; 676 //printf("func accept_timeout() timeout err:%d \n", ret); 677 return ret; 678 } 679 else 680 { 681 ret = errno; 682 printf("func accept_timeout() err:%d \n", ret); 683 return ret; 684 } 685 } 686 687 *connfd = ret; 688 return 0; 689 } 690 //服务器端发送报文 691 int sckServer_send(int connfd, unsigned char *data, int datalen, int timeout) 692 { 693 int ret = 0; 694 695 ret = write_timeout(connfd, timeout); 696 if (ret == 0) 697 { 698 int writed = 0; 699 unsigned char *netdata = ( unsigned char *)malloc(datalen + 4); 700 if ( netdata == NULL) 701 { 702 ret = Sck_ErrMalloc; 703 printf("func sckServer_send() mlloc Err:%d\n ", ret); 704 return ret; 705 } 706 int netlen = htonl(datalen); 707 memcpy(netdata, &netlen, 4); 708 memcpy(netdata+4, data, datalen); 709 710 writed = writen(connfd, netdata, datalen + 4); 711 if (writed < (datalen + 4) ) 712 { 713 if (netdata != NULL) 714 { 715 free(netdata); 716 netdata = NULL; 717 } 718 return writed; 719 } 720 721 } 722 723 if (ret < 0) 724 { 725 //失败返回-1,超时返回-1并且errno = ETIMEDOUT 726 if (ret == -1 && errno == ETIMEDOUT) 727 { 728 ret = Sck_ErrTimeOut; 729 printf("func sckServer_send() mlloc Err:%d\n ", ret); 730 return ret; 731 } 732 return ret; 733 } 734 735 return ret; 736 } 737 //服务器端端接受报文 738 int sckServer_rev(int connfd, unsigned char *out, int *outlen, int timeout) 739 { 740 741 int ret = 0; 742 743 if (out==NULL || outlen==NULL) 744 { 745 ret = Sck_ErrParam; 746 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 747 return ret; 748 } 749 750 ret = read_timeout(connfd, timeout); //bugs modify bombing 751 if (ret != 0) 752 { 753 if (ret==-1 || errno == ETIMEDOUT) 754 { 755 ret = Sck_ErrTimeOut; 756 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 757 return ret; 758 } 759 else 760 { 761 printf("func sckClient_rev() timeout , err:%d \n", Sck_ErrTimeOut); 762 return ret; 763 } 764 } 765 766 int netdatalen = 0; 767 ret = readn(connfd, &netdatalen, 4); //读包头 4个字节 768 if (ret == -1) 769 { 770 printf("func readn() err:%d \n", ret); 771 return ret; 772 } 773 else if (ret < 4) 774 { 775 ret = Sck_ErrPeerClosed; 776 printf("func readn() err peer closed:%d \n", ret); 777 return ret; 778 } 779 780 int n; 781 n = ntohl(netdatalen); 782 ret = readn(connfd, out, n); //根据长度读数据 783 if (ret == -1) 784 { 785 printf("func readn() err:%d \n", ret); 786 return ret; 787 } 788 else if (ret < n) 789 { 790 ret = Sck_ErrPeerClosed; 791 printf("func readn() err peer closed:%d \n", ret); 792 return ret; 793 } 794 795 *outlen = n; 796 797 return 0; 798 } 799 800 //服务器端环境释放 801 int sckServer_destroy(void *handle) 802 { 803 return 0; 804 }
服务器:
1 #include <unistd.h> 2 #include <sys/types.h> 3 #include <signal.h> 4 #include <sys/wait.h> 5 6 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <errno.h> 10 #include <string.h> 11 #include <pthread.h> 12 13 #include "commsocket.h" 14 15 #include "myipc_sem.h" 16 #include "myipc_shm.h" 17 18 pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER; 19 20 21 int g_key = 0x3333; 22 23 #define ERR_EXIT(m) \ 24 do \ 25 { \ 26 perror(m); \ 27 exit(EXIT_FAILURE); \ 28 } while(0) 29 30 31 #include <signal.h> 32 33 void handle(int signum) 34 { 35 int pid = 0; 36 printf("recv signum:%d \n", signum); 37 38 //避免僵尸进程 39 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 40 { 41 printf("退出子进程pid%d \n", pid); 42 fflush(stdout); 43 } 44 } 45 46 int srvInit() 47 { 48 //共享内存创建 49 int ret = 0; 50 int shmhdl = 0; 51 ret = IPC_CreatShm(".", sizeof(int), &shmhdl); 52 if (ret != 0) 53 { 54 printf("func IPC_CreatShm() err:%d \n", ret); 55 return ret; 56 } 57 58 59 //信号量的创建 60 int semid = 0; 61 ret = sem_creat(g_key, &semid); 62 if (ret != 0) 63 { 64 printf("func sem_creat() err:%d,重新按照open打开信号量 \n", ret); 65 if (ret == SEMERR_EEXIST) 66 { 67 ret = sem_open(g_key, &semid); 68 if (ret != 0) 69 { 70 printf("按照打开的方式,重新获取sem失败:%d \n", ret); 71 return ret; 72 } 73 } 74 else 75 { 76 return ret; 77 } 78 79 } 80 81 int val = 0; 82 ret = sem_getval(semid, &val); 83 if (ret != 0 ) 84 { 85 printf("func sem_getval() err:%d \n", ret); 86 return ret; 87 } 88 printf("sem val:%d\n", val); 89 return 0; 90 91 } 92 93 94 void TestFunc_sem() 95 { 96 int ncount = 0; 97 int ret = 0; 98 int shmhdl = 0; 99 int *addr = NULL; 100 101 int semid = 0; 102 sem_open(g_key, &semid); 103 104 105 sem_p(semid); //临界区开始 106 107 // 108 ret = IPC_CreatShm(".", 0, &shmhdl); 109 110 ret =IPC_MapShm(shmhdl, (void **)&addr); 111 *((int *)addr) = *((int *)addr) + 1; 112 ncount = *((int *)addr); 113 printf("ncount:%d\n", ncount); 114 //addr[0] = addr[0] +1; 115 ret =IPC_UnMapShm(addr); 116 //sleep(2); 117 118 sem_v(semid); //临界区开始 119 // 120 //printf("进程正常退出:%d\n", getpid()); 121 } 122 123 124 void TestFunc_mutex() 125 { 126 int ncount = 0; 127 int ret = 0; 128 int shmhdl = 0; 129 int *addr = NULL; 130 131 int semid = 0; 132 sem_open(g_key, &semid); 133 134 135 //sem_p(semid); //临界区开始 136 pthread_mutex_lock(&mymutex); 137 138 // 139 ret = IPC_CreatShm(".", 0, &shmhdl); 140 141 ret =IPC_MapShm(shmhdl, (void **)&addr); 142 *((int *)addr) = *((int *)addr) + 1; 143 ncount = *((int *)addr); 144 printf("ncount:%d\n", ncount); 145 //addr[0] = addr[0] +1; 146 ret =IPC_UnMapShm(addr); 147 //sleep(2); 148 149 //sem_v(semid); //临界区开始 150 pthread_mutex_unlock(&mymutex); 151 // 152 //printf("进程正常退出:%d\n", getpid()); 153 } 154 155 156 void *thread_routine(void* arg) 157 { 158 int connfd = 0; 159 int ret = 0; 160 161 pthread_detach(pthread_self()); 162 163 if (arg == NULL) 164 { 165 return NULL; 166 } 167 connfd = *((int *)arg); 168 free(arg); 169 170 unsigned char recvbuf[1024]; 171 int recvbuflen = 1024; 172 int wait_seconds = 5; 173 174 175 while(1) 176 { 177 memset(recvbuf, 0, sizeof(recvbuf)); 178 ret = sckServer_rev(connfd, recvbuf, &recvbuflen, wait_seconds); 179 if (ret != 0) 180 { 181 if (ret == Sck_ErrTimeOut) 182 { 183 continue; 184 } 185 printf("func sckServer_rev() err:%d \n", ret); 186 break; 187 } 188 189 TestFunc_mutex(); 190 printf("recvbuf:%s\n", recvbuf); 191 192 // 193 ret = sckServer_send(connfd, recvbuf, recvbuflen, wait_seconds); 194 if (ret != 0) 195 { 196 printf("func sckServer_send() err:%d \n", ret); 197 break; 198 } 199 } 200 close(connfd); 201 return NULL; 202 } 203 204 int main(void) 205 { 206 int ret = 0; 207 int listenfd; 208 209 210 signal(SIGCHLD, handle); 211 signal(SIGPIPE, SIG_IGN); 212 213 //完成共享内存和信号量的创建 214 srvInit(); 215 216 ret = sckServer_init(8001, &listenfd); 217 if (ret != 0) 218 { 219 printf("sckServer_init() err:%d \n", ret); 220 return ret; 221 } 222 223 while(1) 224 { 225 int ret = 0; 226 int wait_seconds = 5; 227 int connfd = 0; 228 229 ret = sckServer_accept(listenfd, &connfd, wait_seconds); 230 if (ret == Sck_ErrTimeOut) 231 { 232 //printf("timeout....\n"); 233 continue; 234 } 235 int tid = 0; 236 237 int *pCon = (int *)malloc(sizeof(int)) ; 238 *pCon = connfd; 239 240 //每来一个连接,需要启动I个线程,线程需要收发报文 241 pthread_create(&tid, NULL, thread_routine, (void *)pCon); 242 243 } 244 245 246 return 0; 247 }
客户端:
1 #include <unistd.h> 2 #include <sys/types.h> 3 //#include <sys/socket.h> 4 //#include <netinet/in.h> 5 //#include <arpa/inet.h> 6 #include <signal.h> 7 #include <sys/wait.h> 8 //#include "sckutil.h" 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <errno.h> 13 #include <string.h> 14 15 #include "commsocket.h" 16 17 void handle(int signum) 18 { 19 int pid = 0; 20 printf("recv signum:%d \n", signum); 21 22 //避免僵尸进程 23 while ((pid = waitpid(-1, NULL, WNOHANG) ) > 0) 24 { 25 printf("退出子进程pid%d \n", pid); 26 fflush(stdout); 27 } 28 } 29 30 31 32 int main() 33 { 34 int ret = 0; 35 void *handle = NULL; 36 //void handle = NULL; 37 int connfd; 38 int i = 0, j = 0; 39 40 signal(SIGCHLD, handle); 41 signal(SIGPIPE, SIG_IGN); //防止 sokcet破裂 42 43 int procnum=10; 44 int loopnum = 100; 45 46 pthread_t tidArray[1024*2]; 47 48 49 50 printf("请输入要创建子进程的个数 : \n"); 51 scanf("%d", &procnum); 52 53 printf("请输入让每个子进程测试多少次 :\n"); 54 scanf("%d", &loopnum); 55 56 57 unsigned char *data = (unsigned char *)"aaaaaafffffffffffssssss"; 58 int datalen = 10; 59 60 unsigned char out[1024]; 61 int outlen = 1024; 62 //客户端环境初始化 63 64 ret = sckCliet_init(&handle, 15, 5, 5, 10); 65 66 for (i=0; i<procnum; i++) 67 { 68 int pid = fork(); 69 if (pid == 0) 70 { 71 ret = sckCliet_getconn(handle, "127.0.0.1", 8001, &connfd); 72 for (j=0; j<loopnum; j++) 73 { 74 //客户端发送报文 75 ret = sckClient_send(handle, connfd, data, datalen); 76 if (ret != 0) 77 { 78 if (ret == Sck_ErrTimeOut) 79 { 80 continue; 81 } 82 break; 83 } 84 //printf("ccccccc\n"); 85 //客户端端接受报文 86 ret = sckClient_rev(handle, connfd, out, &outlen); //10 87 if (ret != 0) 88 { 89 if (ret == Sck_ErrTimeOut) 90 { 91 break; 92 } 93 break; 94 } 95 out[outlen] = '\0'; 96 97 printf("out: %s \n", out); 98 } 99 100 close(connfd); 101 exit(0); //让子进程退出,不参与fork 102 } 103 } 104 105 106 // 客户端环境释放 107 ret = sckClient_destroy(handle); 108 109 //避免僵尸进程 110 int mypid; 111 while ((mypid = waitpid(-1, NULL, WNOHANG) ) > 0) 112 { 113 printf("退出子进程pid%d \n", mypid); 114 fflush(stdout); 115 } 116 117 }