服务器
- 原理过程已经在另一篇文章中说明,此处直接上代码
#include<stdio.h>
#include<pthread.h>
#include<signal.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#define SERVICE_PORT 8888
#define SERVICE_IP "127.0.0.1"
int consume();
void wait_child()//子进程回收函数
{
waitpid(0,NULL,WNOHANG);//客户端退出后回收子进程
}
struct input
{
int buf_num[8];//初始化用于写入来自客户端输入的数据buf_num
char message[32];//初始化用于给客户发送提示信息
int consume_num[7];//初始化传给客户端的每种纸币的数量情况
int surplus_money;//初始化传给客户端剩余的钱
};
struct input *buf;//定义结构体指针变量,用于存放数据
int surplus_money;
int consume(int *my_money_num,int *consume_num)//第一个为传入参数,第二个为传出
参数
{
//第一步:初始化剩余钱数,钱的类型,商品价格,自己拥有的钱
int surplus_money = 0;
int num = 0;
int money[] = { 1,2,5,10,20,50,100 };
int size = sizeof(money) / 4;
int my_size = sizeof(my_money_num) / 4;
int product_price = my_money_num[7];
int i = 6;
int my_money = 0;
//第二步:计算自己的现金
my_money = 100 * my_money_num[6] + 50 * my_money_num[5] + 20 * my_money_num[4] + 10 * my_money_num[3] + 5 * my_money_num[2] + 2 * my_money_num[1] + my_money_num[0];
printf("你有【%d】元\n", my_money);
printf("你的商品价格是:%d",product_price);
//第三步:如果自己的钱>商品的价格,开始从高往底依次扣钱
if (my_money >= product_price)
{
printf("开始扣钱。。。\n");
while (1)
{
if ((product_price -= 100) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 100;
break;
}
}
i--;
while (1)
{
if ((product_price -= 50) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 50;
break;
}
}
i--;
while (1)
{
if ((product_price -= 20) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 20;
break;
}
}
i--;
while (1)
{
if ((product_price -= 10) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 10;
break;
}
}
i--;
while (1)
{
if ((product_price -= 5) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 5;
break;
}
}
i--;
while (1)
{
if ((product_price -= 2) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
product_price += 2;
break;
}
}
i--;
while (1)
{
if ((product_price -= 1) >= 0 && (my_money_num[i]--) > 0)
{
consume_num[i]++;
continue;
}
else
{
break;
}
}
//第四步:计算消耗的钱,和剩余的钱
int consume_money = 100 * consume_num[6] + 50 * consume_num[5] + 20 * consume_num[4] + 10 * consume_num[3] + 5 * consume_num[2] + 2 * consume_num[1] + consume_num[0];
surplus_money = my_money - consume_money;
}
else
{
printf("你的钱不够!!!\n");
}
printf("欢迎下次光临\n");
//第五步:返回出剩余的钱,用于发送给客户端
return surplus_money;
}
int main()
{
struct sockaddr_in service_addr,client_addr;//定义服务器,客户端的结构>体地址名称
buf = (struct input *)malloc(sizeof(struct input));//在堆区开辟空间
char client_ip[16];//存放客户端的ip地址
int num = 1;//表示客户端的连接数目
pid_t pid;
int connfp;//初始化连接套接字
bzero(&service_addr,sizeof(service_addr));//清空service_addr
//下面开始初始化服务器地址的各项信息
service_addr.sin_family = AF_INET;
service_addr.sin_port = htons(SERVICE_PORT);
service_addr.sin_addr.s_addr = inet_addr(SERVICE_IP);
//第一步:先利用socket函数产生一个监听套接字描述符
int sockfp = socket(AF_INET,SOCK_STREAM,0);//协议选取ipv4
if(sockfp == -1)
{
perror("socket error:");
exit(1);
}
//第二步:利用bind函数将sockfp和service_addr绑定在一起,使sockfp这个用>于网络通信的文件描述符监听service_addr所描述的地址和端口号
int bin = bind(sockfp,(struct sockaddr *)&service_addr,sizeof(struct sockaddr));
if(bin == -1)
{
perror("bind error:");
exit(1);
}
//第三步:声明sockfp处于监听状态,最多允许有128个客户端处于连接状态
int list = listen(sockfp,128);
if(list == -1)
{
perror("listen error:");
exit(1);
}
while(1)//循环创建子进程
{
printf("begin to next connect...\n\n");
int size = sizeof(client_addr);
connfp = accept(sockfp,(struct sockaddr *)&client_addr,&size);//当有客户端发起连接时,服务器调用accept接受连接请求,然后阻塞,直到有下一个客户
端请求连接时再调用accept进行接受请求
if(connfp == -1)
{
perror("accept error:");
exit(1);
}
else if(connfp>0);//连接成功时会返回一个新的套接字描述符
{
printf("\n\n[%d] new client is connected successfully!!!\n\n",num++);
}
printf("message is : client ip:%s,port:%d\n",inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),ntohs(client_addr.sin_port));//输出连接客户端的信息
printf("begin to fork\n\n");
pid = fork();
if(pid < 0)
{
perror("fork error");
exit(1);
}
else if(pid == 0)
{
//子进程利用连接套接字connfp进行与客户端的数据交互
close(sockfp);
break;//子进程退出循环去执行下面的操作
}
else
{
//父进程利用监听套接字sockfp等待客户端连接
close(connfp);
printf("开始回收子进程\n");
signal(SIGCHLD,wait_child);
}
}
if(pid == 0)//子进程与客户端进行数据交互
{
printf("i am child,i am receiveing data from client...\n");
while(1)//接受来自客户端的数据,通过计算,发送数据
{
printf("开始read\n");
int r = read(connfp,buf->buf_num,sizeof(buf->buf_num));
if(r == -1)
{
perror("read error:");
exit(1);
}
else if(r == 0)
{
printf("read finish\n");
}
printf("开始执行consume\n");
buf->surplus_money = consume(buf->buf_num,buf->consume_num);
printf("surplus = %d\n",buf->surplus_money);
write(connfp,&buf->surplus_money,sizeof(buf->surplus_money));
sleep(1);
write(connfp,buf->consume_num,sizeof(buf->consume_num));
sleep(1);
strcpy(buf->message,"本次购物完成,是否继续购物?(y/n)");
write(connfp,buf->message,sizeof(buf->message));
sleep(1);
}
}
return 0;
}
客户端
#include<stdio.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<ctype.h>
#define SERVICE_PORT 8888
#define SERVICE_IP "127.0.0.1"
struct input
{
char message[32];//初始化用于写入数据的buf_in
char answer[2];//初始化用于传出数据的buf_out
int num[8];
int consume_num[7];
int surplus;
};
int main()
{
struct sockaddr_in service_addr;//定义服务器结构体地址名称
struct input *buf;//定义结构体指针变量,用于存放数据
buf = (struct input *)malloc(sizeof(struct input));//在堆区开辟空
pthread_rwlock_t rwlock;
bzero(&service_addr,sizeof(service_addr));//清空service_addr
//下面开始初始化服务器地址的各项信息
service_addr.sin_family = AF_INET;
service_addr.sin_port = htons(SERVICE_PORT);
//service_addr.sin_addr.s_addr = htonl(SERVICE_IP);
inet_pton(AF_INET,SERVICE_IP,&service_addr.sin_addr.s_addr);
//第一步:先利用socket函数产生一个监听套接字描述符
int sockfp = socket(AF_INET,SOCK_STREAM,0);//协议选取ipv4
if(sockfp == -1)
{
perror("socket error:");
exit(1);
}
printf("begin to connect\n\n");
//第二步:利用connetc函数发起与服务器的连接
int connfp = connect(sockfp,(struct sockaddr *)&service_addr,sizeof(struct sockaddr));//
if(connfp == -1)
{
perror("bind error:");
exit(1);
}
else if(connfp>0)//连接成功时会返回一个新的套接字描述符
{
printf("You have been connected with service successfully!!!\n\n");
}
while(1)//利用while循环给服务器写数据
{
memset(buf->num,0,sizeof(buf->num));
printf("你已经开始购物!!!\n");
printf("请按顺序输入:你的1元张数,2元张数,5元张数,10元张数,20元>张数,50元张数,100元张数,商品价格。。。\n");
for(int i = 0;i<8;i++)
{
scanf("%d",&buf->num[i]);
}
printf("开始请求服务器...\n");
write(sockfp,buf->num,sizeof(buf->num));
read(sockfp,&buf->surplus,sizeof(buf->surplus));
printf("你还剩[%d]元!\n",buf->surplus);
sleep(1);
read(sockfp,buf->consume_num,sizeof(buf->consume_num));
printf("你的资金消耗情况如下:(顺序为:1元,2元,5元,10元,20元,50>元,100元)\n");
for(int i = 0;i<7;i++)
{
printf("%d, \n",buf->consume_num[i]);
}
sleep(1);
read(sockfp,buf->message,sizeof(buf->message));
printf("message = %s\n",buf->message);
scanf("%s", buf->answer);
printf("answer = %s\n", buf->answer);
if (strcmp(buf->answer, "n") == 0)
{
break;
}
}
return 0;
}
本人大部分代码开放免费,用于交流学习,有bug时还望指出,请勿直接抄袭,谢谢!