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