重点集中在用多线程实现,建立线程特有数据,不会发生数据写入冲突。
实现的功能很简单,客户端连接成功后,输入一个整数,服务端返回它的二进制形式。客户端输入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; }