網路程式設計:服務端處理多個客戶端----多執行緒實現、建立執行緒特有資料.
阿新 • • 發佈:2019-02-04
重點集中在用多執行緒實現,建立執行緒特有資料,不會發生資料寫入衝突。
實現的功能很簡單,客戶端連線成功後,輸入一個整數,服務端返回它的二進位制形式。客戶端輸入0,則主動退出。
三個檔案:
duoxianc.c ,主檔案
binarykey.c,執行緒執行函式及特有資料建立
client.c,客戶端程式
基本概念:
int pthread_once(pthread_once_t *once_control, void (*init)(void));
一次性初始化函式,不管有多少個執行緒執行,只初始化一次。
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
建立資料概念
int pthread_setspecific(pthread_key_t key, const void *value);
為資料概念分配記憶體
void *pthread_getspecific(pthread_key_t key);
查詢為資料概念分配的記憶體
duoxianc.c
#include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> #include <stdlib.h> #define PORT 6666 #define SIZE 1024 int _count = 1; extern char* binarystyle(int client_socket); int Creat_socket() //建立套接字和初始化以及監聽函式 { int listen_socket = socket(AF_INET, SOCK_STREAM, 0); //建立一個負責監聽的套接字 if(listen_socket == -1) { perror("socket"); return -1; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; /* Internet地址族 */ addr.sin_port = htons(PORT); /* 埠號 */ addr.sin_addr.s_addr = htonl(INADDR_ANY); /* IP地址 */ int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr)); //連線 if(ret == -1) { perror("bind"); return -1; } ret = listen(listen_socket, 5); //監聽 if(ret == -1) { perror("listen"); return -1; } return listen_socket; } int wait_client(int listen_socket) { struct sockaddr_in cliaddr; int addrlen = sizeof(cliaddr); int client_socket = accept(listen_socket, (struct sockaddr *)&cliaddr, &addrlen); //建立一個和客戶端交流的套接字 if(client_socket == -1) { perror("accept"); return -1; } printf("接收到第%d個客戶端哈:%s\n",_count++, inet_ntoa(cliaddr.sin_addr)); return client_socket; } void* talk_client(void * _socket) //執行緒執行函式,與客戶端交流 { int socket = *(int*) _socket; char *buf; while(1) { buf = binarystyle(socket);//binarykey.c檔案中的函式 if(buf == NULL) break; printf("%s\n", buf); write(socket, buf, strlen(buf)); } printf("客戶端退出啦哈\n"); close(socket); } int main() { int listen_socket = Creat_socket(); while(1) { int client_socket = wait_client(listen_socket); pthread_t id; pthread_create(&id, NULL, talk_client, (void *)&client_socket); //建立一個執行緒,來處理客戶端。 pthread_detach(id); //把執行緒分離出去。 } close(listen_socket); return 0; }
binarykey.c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/socket.h> #include <string.h> #include <unistd.h> #define SIZE 50 static pthread_once_t once = PTHREAD_ONCE_INIT;//一次性初始化函式變數 static pthread_key_t binarykey;//建立的資料概念 static void destructor(void * buf)//執行緒銷燬後執行的解構函式 { free(buf); } static void createkey() { int s = pthread_key_create(&binarykey,destructor);//建立key if(s != 0) printf("create error\n"); } char *binarystyle(int client_socket)//引數之後新增 { int s; char *buf; s = pthread_once(&once,createkey);//一次性初始化函式,不管有多少執行緒只執行一次, pthread_key_create經常在pthread_once裡連用 if(s != 0) printf("create error\n"); buf = pthread_getspecific(binarykey);//查詢是否為該資料概念分配記憶體 if(buf == NULL) { buf = (char*)malloc(SIZE); if(buf == NULL) printf("malloc fail\n"); s = pthread_setspecific(binarykey,buf);//為該資料概念分配特有記憶體 if(s != 0) printf("setspecific fail\n"); } int ret = read(client_socket,buf,SIZE-1); if(ret == -1) printf("read fail\n"); if(ret == 0) return NULL; buf[ret] = '\0'; int temp = atoi(buf); if(temp == 0)//如果客戶端輸入0,則退出 return NULL; int count = 32; int i = 0; while(count--) { if(1<<count & temp) buf[i++ ] = '1'; else buf[i++ ] = '0'; if(count %8 == 0) buf[i++ ] = ' '; } buf[i] = '\0'; return buf; }
client.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#define PORT 6666
#define SIZE 50
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket\n");
return -1;
}
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
char c[] = "127.0.0.1";
inet_pton(AF_INET,c,(void *)&addr.sin_addr);
int ret = connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(ret == -1)
{
perror("connect\n");
return -1;
}
printf("客戶端連線成功了哈\n");
char buf[SIZE];
while(1)
{
printf("請輸入你想輸入的:");
scanf("%s",buf);
write(sockfd,buf,strlen(buf));
if(atoi(buf) == 0)
break;
int ret = read(sockfd,buf,sizeof(buf));
if(ret == -1)
{
perror("read\n");
return -1;
}
buf[ret] = '\0';
printf("二進位制形式:%s\n",buf);
}
close(sockfd);
return 0;
}