我想通过服务器客户端中的套接字以JSON格式发送数据 以C编写的申请。
我正在使用json-c / libjson库来处理C中的JSON数据 应用
通过处理一些教程,我能够创建JSON对象并能够成功解析它。
现在我想使用JSON数据格式进行服务器客户端的通信。
以下是我的服务器和客户端代码的一部分
server.c
int main()
{
int listenfd = 0, connfd = 0; //related with the server
struct sockaddr_in serv_addr;
//json_object * jobj;
uint8_t buf[158], i;
memset(&buf, '0', sizeof(buf));
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(8888);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
printf("binding\n");
listen(listenfd, 5);
printf("listening\n");
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
printf("Reading from client\n");
while ( (read(connfd, buf, 157)) > 0 )
{
for ( i = 0; i < 157; i++ )
//printf("%s\n", json_object_to_json_string(jobj));
//json_parse(jobj);
printf("%d\n", buf[i]);
}
return 0;
}
client.c
int main()
{
char* str;
int fd = 0;
struct sockaddr_in demoserverAddr;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
printf("Error : Could not create socket\n");
return 1;
}
else
{
demoserverAddr.sin_family = AF_INET;
demoserverAddr.sin_port = htons(8888);
demoserverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(demoserverAddr.sin_zero, '\0', sizeof(demoserverAddr.sin_zero));
}
if (connect(fd, (const struct sockaddr *)&demoserverAddr, sizeof(demoserverAddr)) < 0)
{
printf("ERROR connecting to server\n");
return 1;
}
/*Creating a json object*/
json_object *jobj = json_object_new_object();
/*Creating a json string*/
json_object *jstring = json_object_new_string("Joys of Programming");
/*Creating a json integer*/
json_object *jint = json_object_new_int(10);
/*Creating a json boolean*/
json_object *jboolean = json_object_new_boolean(1);
/*Creating a json double*/
json_object *jdouble = json_object_new_double(2.14);
/*Creating a json array*/
json_object *jarray = json_object_new_array();
/*Creating json strings*/
json_object *jstring1 = json_object_new_string("c");
json_object *jstring2 = json_object_new_string("c++");
json_object *jstring3 = json_object_new_string("php");
/*Adding the above created json strings to the array*/
json_object_array_add(jarray,jstring1);
json_object_array_add(jarray,jstring2);
json_object_array_add(jarray,jstring3);
/*Form the json object*/
/*Each of these is like a key value pair*/
json_object_object_add(jobj,"Site Name", jstring);
json_object_object_add(jobj,"Technical blog", jboolean);
json_object_object_add(jobj,"Average posts per day", jdouble);
json_object_object_add(jobj,"Number of posts", jint);
json_object_object_add(jobj,"Categories", jarray);
printf("Size of JSON object- %lu\n", sizeof(jobj));
printf("Size of JSON_TO_STRING- %lu,\n %s\n", sizeof(json_object_to_json_string(jobj)), json_object_to_json_string(jobj));
//printf("Size of string- %lu\n", sizeof(json_object_to_json_string(jobj)));
write(fd, json_object_to_json_string(jobj), 157);
printf("Written data\n");
return 0;
}
我想将json_object jobj从客户端发送到服务器。 怎么做?
我尝试过的一些事情:
当我使用write(fd, jobj, sizeof(jobj))
时,当我在服务器上接收数据时,客户端只发送8个字节,其他字符为空。
当我使用write(fd, json_object_to_json_string(jobj), 157)
时,我只能发送完整的json_object jobj,其中157是该jobj对象中的总字符数。
在服务器端,如果我使用read(connfd, jobj, sizeof(jobj))
,那么我只能接收8个字节(在客户端我正在使用write(fd, jobj, sizeof(jobj))
)。
如果我使用上面的server.c,我可以收到完整的JSON对象(如果我已经知道该对象中的字符数)。但它采用原始格式(逐字节接收)。
如何从客户端发送完整的json_object jobj?
如何在服务器端接收完整的json_object jobj?
答案 0 :(得分:4)
1)jobj是指针,所以当你使用
时write(fd, jobj, sizeof(jobj))
你正在为那个对象写一个指针,而不是那个对象。
3)和以前一样。
也许你应该尝试用类似
的方式发送它if (write(fd, jobj, sizeof(*jobj)) == -1)
/* error handler /*
在接收方,你应该做一个for循环,比如
for (;;)
{
r = read(fd, jobj, SIZE);
if (r == -1)
/*error handler*/
if (r == 0)
break;
}
如果您知道json的最大SIZE,或者组合 malloc()和 realloc(),否则
编辑:
我这样做了,现在效果很好。
<强> client.c 强>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <json/json.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main()
{
/* all previous code until
printf("Size of string- %lu\n", sizeof(json_object_to_json_string(jobj)))*/
char temp_buff[MAX_SIZE];
if (strcpy(temp_buff, json_object_to_json_string(jobj)) == NULL)
{
perror("strcpy");
return EXIT_FAILURE;
}
if (write(fd, temp_buff, strlen(temp_buff)) == -1)
{
perror("write");
return EXIT_FAILURE;
}
printf("Written data\n");
return EXIT_SUCCESS;
}
<强> server.c 强>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <json/json.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main()
{
/* all previous code until
printf("Reading from client\n"); */
ssize_t r;
char buff[MAX_SIZE];
for (;;)
{
r = read(connfd, buff, MAX_SIZE);
if (r == -1)
{
perror("read");
return EXIT_FAILURE;
}
if (r == 0)
break;
printf("READ: %s\n", buff);
}
return EXIT_SUCCESS;
}
MAX_SIZE是一个指定最大缓冲区长度的宏,可以根据需要进行设置。
请在下次粘贴所有代码(包括#include ...
)并正确缩进。
答案 1 :(得分:0)
要使用TCP套接字消息,您可以让客户端和服务器学习如何解释消息。
例如,HTTP使用2个字符\ r \ n作为消息的结尾 另一种选择是在消息之前发送消息的大小。
这是使用JSON Jansson库执行此操作的解决方案。 它将大小添加为一系列字符(例如&#34; 123&#34;,稍后解析为整数123),添加字符&#34;#&#34;作为大小标题的结尾,然后是JSON对象的JSON文本表示(由Jansson库定义)
size_t socket_t::write(json_t *json)
{
char *buf_json = NULL;
std::string buf_send;
size_t size_json;
//get char* from json_t
buf_json = json_dumps(json, JSON_PRESERVE_ORDER);
size_json = strlen(buf_json);
//construct send buffer, adding a header with size in bytes of JSON and # terminator
buf_send = std::to_string(static_cast<long long unsigned int>(size_json));
buf_send += "#";
buf_send += std::string(buf_json);
this->write(buf_send.data(), buf_send.size());
free(buf_json);
return buf_send.size();
}
阅读完成
json_t * socket_t::read()
{
int recv_size; // size in bytes received or -1 on error
const int size_buf = 20;
char buf[size_buf];
//peek header
if ((recv_size = recv(m_socket, buf, size_buf, MSG_PEEK)) == -1)
{
std::cout << "recv error: " << strerror(errno) << std::endl;
}
//get size of JSON message
std::string str(buf);
size_t pos = str.find("#");
std::string str_header(str.substr(0, pos));
//parse header
if ((recv_size = recv(m_socket, buf, str_header.size() + 1, 0)) == -1)
{
std::cout << "recv error: " << strerror(errno) << std::endl;
}
//sanity check
buf[recv_size - 1] = '\0';
assert(str_header.compare(buf) == 0);
size_t size_json = static_cast<size_t>(std::stoull(str_header));
std::string str_buf = read_all(size_json);
//terminate buffer with size
std::string str_json = str_buf.substr(0, size_json);
//construct JSON
json_error_t *err = NULL;
json_t *json = json_loadb(str_json.data(), str_json.size(), JSON_PRESERVE_ORDER, err);
return json;
}
这是在
中实现的