网络编程:服务端处理多个客户端----多线程实现、建立线程特有数据.

重点集中在用多线程实现,建立线程特有数据,不会发生数据写入冲突。

实现的功能很简单,客户端连接成功后,输入一个整数,服务端返回它的二进制形式。客户端输入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;
}





猜你喜欢

转载自blog.csdn.net/znzxc/article/details/80328952