1. 程式人生 > >網路程式設計:服務端處理多個客戶端----多執行緒實現、建立執行緒特有資料.

網路程式設計:服務端處理多個客戶端----多執行緒實現、建立執行緒特有資料.

重點集中在用多執行緒實現,建立執行緒特有資料,不會發生資料寫入衝突。

實現的功能很簡單,客戶端連線成功後,輸入一個整數,服務端返回它的二進位制形式。客戶端輸入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;
}