C WEBサーバ側の通信受信を実現

7648 ワード

本稿は「Minaがカスタムプロトコルを実現する通信」サーバ側の解釈と拡張である.
サーバ側コードはサードパーティのオープンソースやビジネスのコードライブラリを使用しない前提の下で、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