First of all, I would like to know if there is any difference (execution-time) in C between:
- GET request made by using cURL
- GET request make by using sockets (BSD sockets)
Second, I've done a C program which parses a XML file (without using any xml-specific library) and makes a GET request with the parsed info as it follows:
http://www.example.com/k=content1|content2|content3
http://www.example.com/k=content4|content5|content6
and so on...
My XML file looks like this:
<tag1>
<tag2>
<Server>
<Host>content1</Host>
<User>content2</User>
<Pass encoding="base64">content3</Pass>
</Server>
<Server>
<Host>content4</Host>
<User>content5</User>
<Pass encoding="base64">content6</Pass>
</Server>
<Server>
<Host>content7</Host>
<User>content8</User>
<Pass encoding="base64">content9</Pass>
</Server>
</tag2>
</tag1>
My code uses just one function as this is how I want it done (without any parameter). Could you please answer my first question and provide some improvements / advices regarding my code ? ( what would you do / use / delete ). I would like to get a response regarding the GET requests then anything else if possible.
The code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <curl/curl.h>
#define keyurl "http://www.link.com"
int getKeyVal(char *key);
// return data from the server
struct return_string {
char *ptr;
size_t len;
};
// utility functions
size_t accumulate(void *ptr, size_t size, size_t nmemb, struct return_string *s);
void init_string(struct return_string *s);
/* get the <key> */
int getKeyVal(char *key)
{
CURL *curl;
CURLcode res;
char url[128];
sprintf(url, "%s/k=%s", keyurl, key);
curl = curl_easy_init();
if (curl) {
struct return_string s;
init_string(&s);
curl_easy_setopt(curl, CURLOPT_URL, keyurl);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, accumulate);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
printf("result: %s\n", s.ptr);
free(s.ptr);
curl_easy_cleanup(curl);
}
else {
res = -99;
}
return(res);
}
/* Initialize the string handler so that it is thread safe */
void init_string(struct return_string *s)
{
s->len = 0;
s->ptr = malloc(s->len + 1);
if (s->ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(-1);
}
s->ptr[0] = '0円';
}
/* Use the "writer" to accumulate text until done */
size_t accumulate(void *ptr, size_t size, size_t nmemb, struct return_string *s)
{
size_t new_len = s->len + size*nmemb;
s->ptr = realloc(s->ptr, new_len + 1);
if (s->ptr == NULL) {
fprintf(stderr, "realloc() failed\n");
exit(-1);
}
memcpy(s->ptr + s->len, ptr, size*nmemb);
s->ptr[new_len] = '0円';
s->len = new_len;
return size*nmemb;
}
int getContent()
{
//constants for reading the XML file
char *buffer = 0;
char finalRequest[200];
long length;
FILE *xmlFile = fopen("C:/Users/IEUser/Desktop/rs.xml", "r");
//constants for parsing XML
const char *HOSTSTART = "<Host>";
const char *HOSTEND = "</Host>";
const char *USERSTART = "<User>";
const char *USEREND = "</User>";
const char *PASSSTART = "<Pass encoding=\"base64\">";
const char *PASSEND = "</Pass>";
char *target_host = NULL, *target_user = NULL, *target_pass = NULL, *start, *end;
//read the xml file
if (xmlFile)
{
fseek(xmlFile, 0, SEEK_END);
length = ftell(xmlFile);
fseek(xmlFile, 0, SEEK_SET);
buffer = malloc(length);
if (buffer)
{
fread(buffer, 1, length, xmlFile);
}
fclose(xmlFile);
if (!buffer) exit(1);
}
start = buffer;
while (1) {
//get the HOST
if (start = strstr(start, HOSTSTART))
{
start += strlen(HOSTSTART);
if (end = strstr(start, HOSTEND))
{
target_host = (char *)malloc(end - start + 1);
memcpy(target_host, start, end - start);
target_host[end - start] = '0円';
}
}
else {
break;
}
//get the USER
if (start = strstr(start, USERSTART))
{
start += strlen(USERSTART);
if (end = strstr(start, USEREND))
{
target_user = (char *)malloc(end - start + 1);
memcpy(target_user, start, end - start);
target_user[end - start] = '0円';
}
}
//get the PASS
if (start = strstr(start, PASSSTART))
{
start += strlen(PASSSTART);
if (end = strstr(start, PASSEND))
{
target_pass = (char *)malloc(end - start + 1);
memcpy(target_pass, start, end - start);
target_pass[end - start] = '0円';
}
}
//send the requested string in the desired format to finalRequest[]
//k=host|user|password
strcpy(finalRequest, target_host);
strcat(finalRequest, "|");
strcat(finalRequest, target_user);
strcat(finalRequest, "|");
strcat(finalRequest, target_pass);
printf("%s", finalRequest);
printf("\n\n");
getKeyVal(finalRequest);
}
return 0;
}
int main()
{
getContent();
return 0;
}
-
2\$\begingroup\$ A start would be timing both options multiple times. \$\endgroup\$Mast– Mast ♦2015年07月07日 10:05:00 +00:00Commented Jul 7, 2015 at 10:05
-
\$\begingroup\$ As Mast put it, there's only one way to find out. There are many variables in such a broad statement. It could vary by architecture, network, kernel etc. \$\endgroup\$jacwah– jacwah2015年07月07日 10:23:23 +00:00Commented Jul 7, 2015 at 10:23
-
\$\begingroup\$ Any speed benefit of either would be dwarfed by the latency of the connection, surely. Propagation delay across a network connection, even a local one ? \$\endgroup\$mckenzm– mckenzm2015年07月07日 12:39:52 +00:00Commented Jul 7, 2015 at 12:39
1 Answer 1
Don't use forward declarations of functions when you don't need to. If the parameters change, you have to edit two locations in your code. The only time when you actually need them is when two functions both reference each other.
Improve the readability of your code by putting newlines in-between unrelated parts of the code. For instance, between function definitions and between definitions and blocks of #include
s. I also like putting newlines before and after if
s and loops.
I expect a function called getX
to return data to the caller, either through return value or pointer parameter. Niether getKeyVal
or getContent
follow this expectation. getKeyVal
could be called sendRequest
, which would better describe it's behavior because it doesn't return a key/value pair.
I would refactor getContent
to actually return finalRequest
and then call getKeyVal
/sendRequest
from main
with it. Have one function that does one thing, not one function that calls everything else (that's what main
is for!).
-
\$\begingroup\$ could you please be more specific about the first and the second advices ? I've noted the second one and will update the final version as I will get it fully done. \$\endgroup\$Grajdeanu Alex– Grajdeanu Alex2015年07月07日 11:11:42 +00:00Commented Jul 7, 2015 at 11:11
-
\$\begingroup\$ @Alex You've put
int getKeyVal(char *key);
etc at the top of your code. This doesn't serve any purpose and the compiler will complain if you change one of the declarations ofgetKeyVal
but forget the other. \$\endgroup\$jacwah– jacwah2015年07月07日 11:17:00 +00:00Commented Jul 7, 2015 at 11:17 -
\$\begingroup\$ Ouh, you're right. I completely missed this. Will remove it. What about the last point ? \$\endgroup\$Grajdeanu Alex– Grajdeanu Alex2015年07月07日 11:19:45 +00:00Commented Jul 7, 2015 at 11:19