網路程式設計三---多執行緒/程序解決併發問題
阿新 • • 發佈:2019-01-01
程式每當客戶端發起一個連線時,服務端接受客戶端連線accpet返回成功後,都建立一個執行緒,並將返回的客戶端的連線描述符fd傳遞給執行緒處理函式,線上程的處理函式doRead處理客戶端資料的收發。需要注意的是pthread_create傳遞的第四個引數傳遞的是將long型別的資料強轉成void *型別的資料,為什麼是long型別不是int型呢?這個在沒個機器上可能都不一樣,在筆者的機器上,int是4個位元組,而void*型別是8個位元組,所以必須將socket描述符定義成8個位元組long型別,否則int型裝成long型別編譯器報錯,此外需要注意的是這裡傳遞的不是clientfd的地址,如果傳遞了clientfd的地址,那麼每當來一個連線的時候,變了clientfd都會被改寫,而執行緒是共享程序的記憶體空間的,也就是說吐過傳遞了clienfd的地址所有執行緒都會使用同一個clienfd,到時其他客戶端無法和服務端通訊。#include <netinet/in.h> #include <sys/socket.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <pthread.h> #include <netdb.h> void* doRead(void* arg) { long connfd = (long)arg; char recvBuf[101] = ""; int n = 0; while((n = recv(connfd,recvBuf, sizeof(recvBuf),0 )) > 0) { printf("number of receive bytes = %d.\n", n); //傳送資料 send(connfd, recvBuf, n, 0); char* bufTmp = recvBuf; while(*bufTmp != '\r' && *bufTmp !='\n') bufTmp++; *bufTmp = '\0'; if(strcmp(recvBuf, "quit") == 0) { break; } } close(connfd); return NULL; } int main() { struct sockaddr_in sockaddr; pthread_t thread_id; int one =1; int ret = 0; bzero(&sockaddr, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(8080); sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); long clientfd; int listenfd = socket(AF_INET, SOCK_STREAM, 0); //建立一個socket //將該套接字的繫結埠設為可重用 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*) &one,(socklen_t)sizeof(one)); if(bind(listenfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { perror("bind error"); return -1; } ret = listen(listenfd, 16); if(ret < 0) { perror("listen failed.\n"); return -1; } struct sockaddr_in clientAdd; socklen_t len = sizeof(clientAdd); while(1) { clientfd = accept(listenfd, (struct sockaddr *)&clientAdd, &len); if(clientfd < 0) { perror("accept this time"); continue; } if(clientfd > 0) { //由於同一個程序內的所有執行緒共享記憶體和變數,因此在傳遞引數時需作特殊處理,值傳遞 pthread_create(&thread_id, NULL, doRead, (void *)clientfd); printf("thread %d created.\n",thread_id ); pthread_detach(thread_id); } } close(listenfd); return 0; }