マングースを使用して特定のプロジェクト用の非同期サーバーを開発しています。リクエストを受け取ってすぐに応答し、必要なすべての解析を行ってから、元のリクエストで渡された URL に応答します。
リクエスト受付部分は完璧です。ただし、応答は別の話です。
プログラム全体をここに置くことはできませんが (妥当性の問題)、問題が実証できるようにレプリカを作成することができました。
/*
* xmlcrlth.c
*
* Created on: Jun 28, 2012
* Author: mfaraz
*/
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <curl/curl.h>
#include <libxml2/libxml/xmlreader.h>
#include <libxml2/libxml/encoding.h>
#include <libxml2/libxml/xmlwriter.h>
#define MAX_DATA_LEN (140)
#define MAX_XML_LEN (1024)
#define MAX_THREAD_STACK (1024 * 1024)
//#define MY_ENCODING "ISO-8859-1"
#define MY_ENCODING "UTF-8"
#define DEFAULT_THREADS 25
//typedef
struct responseInfo {
pthread_t thread_id; /* ID returned by pthread_create() */
int urlLength; /* The Length of the URL */
int xmlLength; /* The Length of the XML */
char theXML[MAX_XML_LEN]; /* The XML to post */
char theURL[MAX_DATA_LEN]; /* The URL to post to */
};
static void *threadCurl(void *newResponse) {
pthread_detach(pthread_self());
struct responseInfo *thisReponse = (struct responseInfo *) newResponse;
char thisXML[MAX_XML_LEN], thisURL[MAX_DATA_LEN];
CURL *curlResponse; /* cURL variable to perform a Response */
CURLcode curlResCode; /* cURL Response Code */
struct curl_slist *headList = NULL;
int urlLength = strlen(thisReponse->theURL); int xmlLength = strlen(thisReponse->theXML);
printf("Received XML (%d vs %d bytes) using ThreadID %lu\n%s \nto URL (%d vs %d bytes) %s\n", xmlLength, thisReponse->xmlLength, thisReponse->thread_id, thisReponse->theXML, urlLength, thisReponse->urlLength, thisReponse->theURL);
// if (urlLength != thisReponse->urlLength)
strncpy(thisURL, thisReponse->theURL, thisReponse->urlLength);
// if (xmlLength != thisReponse->xmlLength)
strncpy(thisXML, thisReponse->theXML, thisReponse->xmlLength);
/*FILE *filePtr; char fileName[MAX_DATA_LEN] = ""; sprintf(fileName, "%lu", pthread_self());
filePtr = fopen(fileName, "a+");
fprintf(filePtr, "-------------------------\n");
fprintf(filePtr, "ThreadID: %s\n", fileName);
fprintf(filePtr, "OurlLength: %d\tCurlLength: %d\n", thisReponse->urlLength, urlLength);
fprintf(filePtr, "OxmlLength: %d\tCxmlLength: %d\n\n", thisReponse->xmlLength, xmlLength);
fprintf(filePtr, "OrigURL: %s\n", thisReponse->theURL);
fprintf(filePtr, "OrigXML: %s\n", thisReponse->theXML);
fprintf(filePtr, "NewURL: %s\n", thisURL);
fprintf(filePtr, "NewXML: %s\n", thisXML);
fclose(filePtr);//*/
urlLength = strlen(thisURL); xmlLength = strlen(thisXML);
printf("Sending XML (%d bytes) using ThreadID %lu\n%s \nto URL (%d bytes) %s\n", xmlLength, thisReponse->thread_id, thisXML, urlLength, thisURL);
headList = curl_slist_append(headList, "Content-Type: text/xml");
curlResponse = curl_easy_init();
if (curlResponse) {
curl_easy_setopt(curlResponse, CURLOPT_URL, thisURL);
curl_easy_setopt(curlResponse, CURLOPT_HTTPHEADER, headList);
// curl_easy_setopt(curlResponse, CURLOPT_POSTFIELDS, xmlResp);
curl_easy_setopt(curlResponse, CURLOPT_POSTFIELDSIZE, thisReponse->xmlLength);
curl_easy_setopt(curlResponse, CURLOPT_COPYPOSTFIELDS, thisXML);
curl_easy_setopt(curlResponse, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(curlResponse, CURLOPT_TIMEOUT, 30);
curl_easy_setopt(curlResponse, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curlResponse, CURLOPT_FRESH_CONNECT, 1);
curl_easy_setopt(curlResponse, CURLOPT_FORBID_REUSE, 1);
curlResCode = curl_easy_perform(curlResponse);
if (curlResCode) printf("Curl Failed with status: %s!\n", curl_easy_strerror(curlResCode));
curl_easy_cleanup(curlResponse);
} else {
printf("Curl Init Failed!\n");
curlResCode = CURLE_FAILED_INIT;
}
curl_slist_free_all(headList);
free(thisReponse);
pthread_exit(NULL);
// return (int)curlResCode;
}
char *getXML(int failCode, char *failDesc) {
int rc;
xmlTextWriterPtr writer;
xmlBufferPtr buf;
// xmlChar *tmp;
static char xmlResp[1024]; xmlResp[0] = '\0';
/* Create a new XML buffer, to which the XML document will be written */
buf = xmlBufferCreate(); if (buf == NULL) printf("MTU_smac: Error creating the xml buffer\n");
/* Create a new XmlWriter for memory, with no compression.
* Remark: there is no compression for this kind of xmlTextWriter */
writer = xmlNewTextWriterMemory(buf, 0); if (writer == NULL) printf("MTU_smac: Error creating the xml writer\n");
/* Start the document with the xml default for the version,
* encoding ISO 8859-1 and the default for the standalone
* declaration. */
rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartDocument\n");
/* Start an element named "svc_result". Since thist is the first
* element, this will be the root element of the document. */
rc = xmlTextWriterStartElement(writer, (xmlChar *)"svc_result"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartElement\n");
/* Start an element named "sli_rep" as child of svc_result. */
rc = xmlTextWriterStartElement(writer, (xmlChar *)"sli_rep"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartElement\n");
/* Add an attribute with name "version" and value "1.0" to sli_rep. */
rc = xmlTextWriterWriteAttribute(writer, (xmlChar *)"version", (xmlChar *)"3.0.0"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteAttribute\n");
/* Start an element named "pos" as child of sli_rep. */
rc = xmlTextWriterStartElement(writer, (xmlChar *)"pos"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartElement\n");
/* Write an element named "poserr" as child of pos. */
rc = xmlTextWriterStartElement(writer, (xmlChar *)"poserr"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartElement\n");
/* Write an element named "time" as child of poserr. */
rc = xmlTextWriterWriteElement(writer, (xmlChar *)"time", (xmlChar *)"Time will Come here"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteFormatElement\n");
/* Add an attribute with name "utc" and value "+0500" to time. */
rc = xmlTextWriterWriteAttribute(writer, (xmlChar *)"utc", (xmlChar *)"+0500"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteAttribute for utc\n");
/* Write an element named "result" as child of poserr. */
rc = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"result", "%s", failDesc); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteFormatElement\n");
/* Add an attribute with name "utc" and value "+0500" to time. */
rc = xmlTextWriterWriteAttribute(writer, (xmlChar *)"resid", (xmlChar *)failCode); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteAttribute for resid\n");
/* Close the element named poserr. */
rc = xmlTextWriterEndElement(writer); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterEndElement\n");
/* Close the element named pos. */
rc = xmlTextWriterEndElement(writer); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterEndElement\n");
/* Start an element named "extra" as child of sli_rep. */
rc = xmlTextWriterStartElement(writer, (xmlChar *)"extra"); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterStartElement\n");
/* Write an element named "resp_status" as child of extra. */
rc = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"resp_status", "%d", failCode); if (rc < 0) printf("MTU_smac: Error at xmlTextWriterWriteFormatElement\n");
/* Here we could close the elements sli_rep and svc_result using the
* function xmlTextWriterEndElement, but since we do not want to
* write any other elements, we simply call xmlTextWriterEndDocument,
* which will do all the work. */
rc = xmlTextWriterEndDocument(writer);
if (rc < 0) printf("MTU_smac: Error at xmlTextWriterEndDocument\n");
xmlFreeTextWriter(writer);
// printf("%s\n", (const char *) buf->content);
sprintf(xmlResp, "%s", (const char *) buf->content);
xmlBufferFree(buf);
return xmlResp;
}
int postXMLResponse(char *xmlResp, char *theURL) {
int urlLength = strlen(theURL);
if (urlLength == 0) return 0; // No URL...no Tension...!
struct responseInfo *newResponse;
pthread_attr_t theAttribs;
int threadPtr;
// Init the threading
threadPtr = pthread_attr_init(&theAttribs);
if (threadPtr) return threadPtr;
else printf("Thread Initialized!\n");
// Set the Stack size.
threadPtr = pthread_attr_setstacksize(&theAttribs, MAX_THREAD_STACK);
if (threadPtr) return threadPtr;
else printf("Thread Stack Size set!\n");
// Set the Thread as Detachable.
threadPtr = pthread_attr_setdetachstate(&theAttribs, PTHREAD_CREATE_DETACHED);
if (threadPtr) return threadPtr;
// Allocate memory for the responseInfo
newResponse = malloc(sizeof(struct responseInfo));
if (newResponse == NULL) return -1;
else printf("Structure MALLOC'ed!\n");
int xmlLength = strlen(xmlResp); int xmlLength2 = xmlLength;//293;
newResponse->urlLength = urlLength;
newResponse->xmlLength = xmlLength;
strncpy(newResponse->theURL, theURL, urlLength);
strncpy(newResponse->theXML, xmlResp, xmlLength2);
printf("Threading Send XML (%d bytes)\n%s \nto URL (%d bytes) %s\n", xmlLength, newResponse->theXML, urlLength, newResponse->theURL);
threadPtr = pthread_create(&newResponse->thread_id, &theAttribs, &threadCurl, newResponse);
if (threadPtr) return threadPtr;
else printf("Thread Created with ThreadID %lu!\n", newResponse->thread_id);
/*FILE *filePtr; char fileName[MAX_DATA_LEN] = ""; sprintf(fileName, "%lu", newResponse->thread_id);
filePtr = fopen(fileName, "a");
fprintf(filePtr, "ThreadID: %s\n", fileName);
fprintf(filePtr, "urlLength: %d\n", newResponse->urlLength);
fprintf(filePtr, "xmlLength: %d\n", newResponse->xmlLength);
fprintf(filePtr, "URL: %s\n", newResponse->theURL);
fprintf(filePtr, "XML: %s", newResponse->theXML);
fclose(filePtr);//*/
threadPtr = pthread_attr_destroy(&theAttribs);
if (threadPtr) return threadPtr;
else printf("Thread Attributes!\n");
return 0;
}
int main(int argc, char *argv[]) {
long int iLoop, iMaxCount;
curl_global_init(CURL_GLOBAL_ALL);
iMaxCount = DEFAULT_THREADS;
if (argc > 1) {
// printf("Showing Arguments: -\n"); for (iLoop = 1 ; iLoop < argc ; iLoop++) printf("%lu = %s\n", iLoop + 1, argv[iLoop]);
iMaxCount = strtol(argv[1], NULL, 10);
}
for (iLoop = 0 ; iLoop < iMaxCount ; iLoop++) {
postXMLResponse(getXML(iLoop, "All of your base are belong to us!"), "http://localhost:80/response.php");
}
sleep(3);
return 0;
}
ライブラリには「xml2」、「curl」、「pthread」、リンカには「-pthread」を設定する必要があります。セットアップによっては、libxml ライブラリの実際のフォルダーも指定する必要がある場合があります。
プログラムを実行すると、25 個のスレッドを生成しようとします。最初の引数は、テストに適した数値に変更できます。私のテストでは、5 であっても、Web サーバーに到達するリクエストは 3 つだけです。これら 3 つのうち、1 つは URL が破損しており、もう 1 つは XML が破損していました。
スレッドが終了するのを待つために何かが足りないことはわかっています(メインサーバーが停止しないため、それを理解できません)。
誰かここで何か間違ったことを指摘してください!