C WEBサーバ側の通信受信を実現
7648 ワード
本稿は「Minaがカスタムプロトコルを実現する通信」サーバ側の解釈と拡張である.
サーバ側コードはサードパーティのオープンソースやビジネスのコードライブラリを使用しない前提の下で、C言語のカスタマイズによってWEBサーバ側のデータ受信と通信を実現した.単純にTOMCATの単純バージョンと理解できる.
サーバ側SOCKETでの傍受バインディングにより,サーバのREQUESTを傍受したが,コードは以下の通りである.
パケットが傍受されるとhandler_が呼び出されますrequest()関数はパケットの解析と操作フィードバックを行う.著者らは,プログラムの効率的な実行をより良くするために,同時処理をより良くするために,スレッドプールの方法を用いてパケット処理関数の呼び出しを処理した.コードは次のようになります.
本題に戻ります.handler_の場合request()関数の詳細コードは次のとおりです.
このパケットのrequestはGETファイル/faviconが欲しいです.ico. 一般的にHTTPのアクセス方式としてはGET POSTなどがある.簡単に解析するだけでデータREQUESTに対するRESPONSEが作れます.ここでGETとPOSTに対するresponse関数コードは以下の通りである.
同時にカスタムパケットの受信をサポートし、そのデータのパケットフォーマットは文章「Minaカスタムプロトコルの通信を実現する」を参照し、そのデータフォーマットの簡単な図は以下の通りである(javaバージョン).
著者らはdataデータの取得と表示を実現するだけで、著者らはデータを統合し、つなぎ合わせる.仮想ファイルの管理、分散ファイルの処理、サーバの負荷分散などの問題を処理します.
Comming soon.....
詳細コードは添付ファイルを参照してください.
http://dl.vmall.com/c0h39lv1hn
サーバ側コードはサードパーティのオープンソースやビジネスのコードライブラリを使用しない前提の下で、C言語のカスタマイズによってWEBサーバ側のデータ受信と通信を実現した.単純にTOMCATの単純バージョンと理解できる.
サーバ側SOCKETでの傍受バインディングにより,サーバのREQUESTを傍受したが,コードは以下の通りである.
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(SEVERPORT);
int server_socket = socket(PF_INET, SOCK_STREAM, 0);
if (server_socket < 0){
printf("create socket failed!
");
exit(1);
}
/*
int opt = 1;
setsocketopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
*/
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))){
printf("server bind port: %d failed!
", SEVERPORT);
exit(1);
}
if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE)){
printf("server listen failed!
");
exit(1);
}
は、次いで、単純なwhile(1)デッドサイクルを介して、リスニングサーバ側のポートに絶えずアクセスし、コードは以下の通りである.while(1){
int i;
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
if (new_server_socket < 0){
printf("server accept failed!
");
break;
}
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
length = recv(new_server_socket, buffer, BUFFER_SIZE, 0);
if (length < 0){
printf("server receive data failed!
");
}
printf("----package begin----");
printf("client INFO:%s ", inet_ntoa(client_addr.sin_addr));
time_t t = time(NULL);
struct tm *local = localtime(&t);
printf("hour:%d minute:%d second:%d
", local->tm_hour, local->tm_min, local->tm_sec);
/*
for (i = 0; i < BUFFER_SIZE; i++){
printf("%d ", (unsigned char)buffer[i]);
}
*/
printf("----package end----
");
// handler_request(buffer, new_server_socket);
struct comdata cd;
int k;
for(k = 0; k < BUFFER_SIZE; k++)
cd.buffer[k] = buffer[k];
cd.socket_server = new_server_socket;
pool_add_worker(handler_request, &cd);
// close(new_server_socket);
}
パケットが傍受されるとhandler_が呼び出されますrequest()関数はパケットの解析と操作フィードバックを行う.著者らは,プログラムの効率的な実行をより良くするために,同時処理をより良くするために,スレッドプールの方法を用いてパケット処理関数の呼び出しを処理した.コードは次のようになります.
pool_add_worker(handler_request, &cd);
スレッドプールの初期化コードは次のとおりです.pool_init(POOL_MAX_NUMBER);
スレッドプールの詳細コードと解釈は、次の文書に記載するか、ソースコードを直接参照します.本題に戻ります.handler_の場合request()関数の詳細コードは次のとおりです.
void *handler_request(void *arg){
char *request = (*(struct comdata *)arg).buffer;
int socket_server = (*(struct comdata *)arg).socket_server;
// splice_file_request(request, socket_server);
char command[BUFFER_SIZE];
char arguments[BUFFER_SIZE];
if (sscanf(request, "%s%s", command, arguments) != 2){
splice_file_request(request, socket_server);
close(socket_server);
return NULL;
}
printf("handler_cmd: %s
", command);
printf("handler_path: %s
", arguments);
if (strcmp(command, "GET") == 0 || strcmp(command, "POST") == 0)
right_request(request, command, arguments, socket_server);
else
wrong_request(socket_server);
close(socket_server);
return NULL;
}
まず簡単なHTTPアクセスパケットを見てみましょう.----package begin----client INFO:127.0.0.1 hour:11 minute:3 second:39
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8082
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.4 (KHTML, like Gecko) Ubuntu/12.10 Chromium/22.0.1229.94 Chrome/22.0.1229.94 Safari/537.4
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
----package end----
このパケットのrequestはGETファイル/faviconが欲しいです.ico. 一般的にHTTPのアクセス方式としてはGET POSTなどがある.簡単に解析するだけでデータREQUESTに対するRESPONSEが作れます.ここでGETとPOSTに対するresponse関数コードは以下の通りである.
void right_request(char *request, char *command, char *arguments, int socket_server){
char *head = "HTTP/1.0 200 OK\r
";
int len = strlen(head);
if (sendall(socket_server, head, &len) == -1){
printf("sending failed!
");
return;
}
char *content_type = "Content-type: text/plain\r
";
len = strlen(content_type);
if (sendall(socket_server, content_type, &len) == -1){
printf("sending failed!
");
return;
}
char *end = "\r
";
len = strlen(end);
if (sendall(socket_server, end, &len) == -1){
printf("sending failed!
");
return;
}
char info[BUFFER_SIZE];
strcat(info, "return: ");
strcat(info, command);
strcat(info, arguments);
strcat(info, "\r
hello world!\r
");
len = strlen(info);
if (sendall(socket_server, info, &len) == -1){
printf("sending failed!
");
return;
}
}
のアクセスの最終的な効果はブラウザアクセス127.0である.0.1:8082/index.html結果は次のように返されます.return: GET/index.html
hello world!
同時にカスタムパケットの受信をサポートし、そのデータのパケットフォーマットは文章「Minaカスタムプロトコルの通信を実現する」を参照し、そのデータフォーマットの簡単な図は以下の通りである(javaバージョン).
package com.a2.desktop.example5.mina.potocol;
import org.apache.mina.core.buffer.IoBuffer;
/**
*
* @author Chen.Hui
*
*/
public abstract class AbsMessage {
/**
* :
*
* tag | header length | Filename | File length | offset | checksum | temps | data
*
*/
/** Tag:0x00 Tag:0x01 8 bit */
public abstract byte getTag();
/** 2^16 65535 */
public abstract short getHeaderlen();
/** UUID , 8*36=288 bit */
public abstract byte[] getFilename();//
/** 2^32=4GB 32 bit */
public abstract int getFileLen();
/** offset 32 bit */
public abstract int getOffset();
/** MD5 32 bit */
public abstract byte[] getChecksum();
/** 128 bit */
public abstract byte[] getTmp();
/**data 1024bit*/
public abstract IoBuffer getData();
}
そのCエンドサーバパケットの解析コードは以下の通りである.void splice_file_request(char *request, int socket_server){
struct message_head tmp;
char data[DATA_SIZE];
int i;
bzero(&data, sizeof(data));
bzero(&tmp, sizeof(tmp));
tmp.tag = request[0];
tmp.head_length = (unsigned char)request[2]+(unsigned char)request[1]*256;
memcpy(&tmp.file_name, &(request[3]), 36);
tmp.file_name[36]='\0';
tmp.file_length = (unsigned char)request[39]*256*256*256+(unsigned char)request[40]*256*256+(unsigned char)request[41]*256+(unsigned char)request[42];
tmp.offset = (unsigned char)request[43]*256*256*256+(unsigned char)request[44]*256*256+(unsigned char)request[45]*256+(unsigned char)request[46];
memcpy(&tmp.checksum, &(request[47]), 4);
memcpy(&tmp.tmp, &(request[51]), 4);
memcpy(&data, &(request[tmp.head_length]), DATA_SIZE);
for(i = 0; i < DATA_SIZE; i++){
// printf("%2x ", (unsigned char)data[i]);
if (i != 0 && i % 20 == 0)
printf("
");
printf("%2x ", (unsigned char)data[i]);
}
printf("
--head--
");
printf("tag:%d head_length:%d file_name:%s file_length:%d offset:%d checksum:%s
", tmp.tag, tmp.head_length, tmp.file_name, tmp.file_length, tmp.offset, tmp.checksum);
printf("--head--
");
}
著者らはdataデータの取得と表示を実現するだけで、著者らはデータを統合し、つなぎ合わせる.仮想ファイルの管理、分散ファイルの処理、サーバの負荷分散などの問題を処理します.
Comming soon.....
詳細コードは添付ファイルを参照してください.
http://dl.vmall.com/c0h39lv1hn