先来声明下本项目的设计目标吧。项目由已工作的师兄从自己现在所在项目组的任务简化抽象而来。
设计一个基于Socket或基于HTTP的服务器,服务内容是提供一种简单的key/value映射关系的管理与查询
下面的所有操作都是通过结构体Node来传递的:
struct Node {
char key[KEY_SIZE];
char value[VALUE_SIZE];
};
本场景中需要client和server两个程序。
client:
client端只有两种操作:
int AddNode(const struct Node *node); // 将指定的node保存到server上,需要key和value都完整
int GetNode(struct Node *node); // 输入的node需要有完整的key,server负责将这个key对应的value填到node中,或返回不存在。
server:
server端就是接收client的两种请求,然后要么保存node要么查询node并返回值。
以下代码将再上文基础上加入结构体的定义,实现AddNode和GetNode两个功能(为封装为函数,抱歉日后修正),并在server端加入对两种情况的响应。
server.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include"messageStruct.h"
#define MAXLINE 4096
int main(int argc, char** argv)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
MSG info; //定义结构体变量
/*协议域:AF_INET ipv4地址(32位的)与端口号(16位的)的组合
SOCK_STREAM提供面向连接的稳定数据传输,即TCP协议。
参数protocol用来指定socket所使用的传输协议编号。这一参数通常不具体设置,一般设置为0即可。
*/
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
/*
INADDR_ANY绑定默认的网卡ip,
htonl其实是host to network, l 的意思是返回类型是long,将主机的无符号长整形数转换成网络字节顺序。
*/
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(6666);//将一个无符号短整形数从网络字节顺序转换为主机字节顺序。
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
if( listen(listenfd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("======waiting for client's request======\n");
while(1){
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1)
{
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
n = recv(connfd, buff, MAXLINE, 0);
memset(&info,0,sizeof(info));
memcpy(&info,buff,sizeof(info));
printf("recv msg from client:\nkey:%s\nvalue:%s\n", info.key,info.value);
if(info.value[0]=='\n')
{
memcpy(&info.value,"value",sizeof(info.value));
memcpy(buff,&info,sizeof(info));
if( send(connfd, buff, sizeof(buff), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
}
close(connfd);
}
close(listenfd);
}
client.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include"messageStruct.h"
#define MAXLINE 4096
int main(int argc, char** argv)
{
int sockfd, n;
char recvline[4096], sendline[4096];
struct sockaddr_in servaddr;
MSG info; //定义结构体变量
if( argc != 2){
printf("usage: ./client <ipaddress>\n");
exit(0);
}
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(6666);
//inet_pton(int af, const char *src, void *dst); Linux下IP地址转换函数,可以在将IP地址在“点分十进制”和“整数”之间转换
if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
printf("inet_pton error for %s\n",argv[1]);
exit(0);
}
if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
printf("Please input the key string:\n");
memset(info.key,0,sizeof(info.key));
fgets(info.key, 4096, stdin);
printf("Please input the value string, if you'd like to get the value of a key, keep it blank\n");
memset(info.value,0,sizeof(info.value));
fgets(info.value, 4096, stdin);
memset(sendline,0,4096);//清空发送缓存,不清空的话可能导致接收时产生乱码,
memcpy(sendline,&info,sizeof(info)); //结构体转换成字符串
if( send(sockfd, sendline, sizeof(sendline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
exit(0);
}
if(info.value[0]=='\n')
{
memset(recvline,0,4096);
n = recv(sockfd, recvline, MAXLINE, 0);
memset(&info,0,sizeof(info));
memcpy(&info,recvline,sizeof(info));
printf("recv msg from client:\nkey:%s\nvalue:%s\n", info.key,info.value);
}
close(sockfd);
exit(0);
}
messageStruct.h
#define KEY_SIZE 1024
#define VALUE_SIZE 1024
typedef struct Node {
char key[KEY_SIZE];
char value[VALUE_SIZE];
}MSG;