スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Tag:スポンサー広告 

【C/C++】C言語からCurlライブラリを使ってみる

通信モジュールとして有名(?)なCurlもジュールをC言語から使ってみます。

今回はYahoo!JAPANのTOPページに対してhttpリクエストを送り、標準出力にhtmlを出力するといったことをやってみようかと思います。

#include<stdio.h>
#include<string.h>
#include<curl/curl.h>

#define MAX_BUF 640000
char wr_buf[MAX_BUF+1];
int  wr_index;

size_t write_data( void *buffer, size_t size, size_t nmemb, void *userp )
{
  int segsize = size * nmemb;

  if ( wr_index + segsize > MAX_BUF ) {
    *(int *)userp = 1;
    return 0;
  }

  memcpy( (void *)&wr_buf[wr_index], buffer, (size_t)segsize );

  wr_index += segsize;

  wr_buf[wr_index] = 0;  return segsize;
}

int main(void){
    CURL *handle;
    CURLcode ret;
    int wr_error;

    wr_error = 0;
    wr_index = 0;

    handle = curl_easy_init();

    curl_easy_setopt(handle, CURLOPT_URL, "http://www.yahoo.co.jp"); //Yahoo!JAPANのTOPページを指定
    curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&wr_error);
    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);

    ret = curl_easy_perform(handle);

    if(ret == 0)
    {
        printf("%s", wr_buf);
    }

    curl_easy_cleanup(handle);

    return 0;
}

どうやらCURLOPT_WRITEFUNCTIONに指定する関数はcurl.hを読んでみると

/* Function that will be called to store the output (instead of fwrite). The
 * parameters will use fwrite() syntax, make sure to follow them. */
CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),

fwrite形式の関数と同じ形式でしていしてください的なしばりがあるようです

あとはcurl_easy_*系のAPIが提供されているようなのでそちらを使用すると簡単に使うことができそうですね。
上記プログラムをcurl_test.cと言う名前で保存したとします。

コンパイルは
gcc -c curl_test.c

リンクは
gcc curl_test.o /usr/lib/libcurl.so -o curl_test

とします。ただし、/usr/lib/libcurl.soは環境によって読み変えてください。

最後に./curl_testと実行すればYahoo!JAPANのトップページのhtmlが出力されるはずです。
スポンサーサイト
テーマ : プログラミング
ジャンル : コンピュータ

Tag:C/C++  Trackback:0 comment:0 

【C】QUERY_STRINGのような文字列の分解

前回書いたQUERY_STRINGのような文字列の分解のC言語版です。

どれだけいろんなことを自分でやらないといけないのかが分かります。
結構昔に書いたのでやたら懐かしいです。

言ってしまえば前回も今回も単なる文字列の分解ですが、メモ程度に書き残しておきます。


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int amp_separator(const char *string, char **result){
    const char *idx;
    const char *current;
    int count = 0;
    int tmp_index = 0;

    idx = string;
    current = string;

    while(1){
        if(*idx == '&'){
            *result = (char *)malloc(sizeof(char) * count + 1);
            strncpy(*result, current, count);
            current = idx + 1;
            count = 0;
            tmp_index++;
            result++;
        }else if(*idx == '\0'){
            *result = (char *)malloc(sizeof(char) * count + 1);
            strncpy(*result, current, count);
            tmp_index++;
            break;
        }else{
            count++;
        }
        idx++;
    }

    return tmp_index;
}

char *eq_separator(const char *string, const char *key){

    const char *cindex;
    const char *current;
    char *result;
    int count = 0;

    cindex = string;
    current = string;

    while(1){
        if(*cindex == '='){
            result = (char *)malloc(sizeof(char) * count);
            strncpy(result, current, count);
            if(strcmp(result, key) == 0){
                free(result);
                strcpy(result, (cindex + 1));
                return result;
            }else{
                free(result);
                break;
            }
        }else if(*cindex == '\0'){
            break;
        }else{
            count++;
        }
        cindex++;
    }

    return NULL;
}

char *getValue(char *query, char *key){
    char *test[10];
    int count_token;
    int i;
    char *ret_val;

    count_token = amp_separator(query, test);

    for(i = 0; i < count_token; i++){
        ret_val = eq_separator(test[i], key);
        if(ret_val != NULL){
            return ret_val;
        }else{
            free(ret_val);
        }
        free(test[i]);
    }


    return NULL;
}

int main(void){
    char *query = "age=23&weight=80";
    char *key = "age";
    char *ret;

    ret = getValue(query, key);

    if(ret != NULL){
        printf("%s\n", ret);
    }

    return 0;
}


C++で書くことの利点はいくつかあげましたが、Cで書く利点はapxsコマンドが作ってくれるMakefileとかを気にしないでそのまま使える点ですかね。

つまりそんなにあげるほど利点はないということですかね。
何となく暇つぶしに書くにはもってこいの題材くらいでしょうかね。

Tag:C/C++  Trackback:0 comment:0 

【C++】ApacheAPIから取得できるQUERY_STRINGのような文字列の分解

ApacheAPIを使い取得することができるQUERY_STRING

b=3&a=2&test=hoge&test2=hogehoge

こんな感じの文字列です。

余談ですが

query = apr_table_get(r->subprocess_env, "QUERY_STRING");

というApacheAPIで取得します。

これを分解して欲しいリクエストパラメータの値を取得するためのクラスを簡単に書いてみました。

いきなりApacheモジュールで使うのではなく上記のような文字列を分解してみるくらいの楽な感じでかきました。


#include<iostream>
#include<string>
#include<map>
using namespace std;

class Params{
    map<string, string> params;
    string original_str;
    void insertMap(string str);
    void cutParams();
  public:
    Params(string str){
        this->original_str = str;
        this->cutParams();
    }   

    string getParam(string key);
};

void Params::insertMap(string str){
    string key;
    string value;
    int eql_idx;

    eql_idx = str.find('=', 0);
    if(eql_idx != string::npos){
        key.assign(str, 0, eql_idx);
        value.assign(str, eql_idx + 1, str.length() - eql_idx);
        this->params.insert(pair<string, string>(key, value));
    }  
}

void Params::cutParams(){
    string str = this->original_str;
    string token;
    int amp_idx = 0;
    int next_amp;

    while(1){
        next_amp = str.find('&', amp_idx);
        if(next_amp != string::npos){
            token.assign(str, amp_idx, next_amp - amp_idx);
            this->insertMap(token);
        }else{
            token.assign(str, amp_idx, str.length() - amp_idx);
            this->insertMap(token);
            break;
        }  
        amp_idx = next_amp + 1;
    }  
}

string Params::getParam(string str){
    map<string, string>::iterator p;

    p = this->params.find(str);

    if(p != this->params.end()){
        return p->second;
    }else{
        return "\0";
    }  
}

int main(void){
    Params p("b=3&a=2&test=hoge&test2=hogehoge");

    cout << p.getParam("test") << endl;
  
    return 0;
}


以前Cでも似たようなことを書いたことがありますが、C++で書く大きな利点は

1.stringやmapなどSTLが使える
2.STLに限らずBoostなど有用なライブラリが使える

ですね。

Tag:C/C++  Trackback:0 comment:0 

【C】UnixDomainにおけるプロセス間の通信

サーバとクライアントにおける通信を理解するためのプログラミング例

通常サーバとクライアントの通信というとWebサーバとWebブラウザとの通信を思い浮かべてしまいます。

これをもう少し噛み砕くと「Webサーバの役目を果たすプログラム」と「Webブラウザの役目を果たすプログラム」との通信になります。

つまり「プロセス間における通信」と持って行くことができそう。

プロセス間の通信の方法の一つに「ソケット通信」というものがあります。
ソケットに関して詳しくはググって欲しいのですが、簡単に説明するとプログラム同士が通信するためのインターフェースですね。

電気ケーブルとかのソケットと考えるとイメージ付けやすいかも知れません。

今回はWebサーバとWebブラウザのようなインターネットを通してのプロセス間の通信ではなくて、

同じOS内でのプロセス間の通信を考えてみます。

これを

「UnixDomainにおけるプロセス間の通信」

といいます。

あんまり目立たないけどコマンドを打たなくてもOS内ではいろんなプログラムが動いてて、それらがたくさん通信してますよね。

今回はシンプルに簡単なメッセージをやり取りするサーバ、クライアントモデルで作ってみました。

あるファイルをソケットとし、そのソケットを通してメッセージのやり取りを行う
今回の例ではserver_socketというファイルをソケットとして通して通信を行う

ただし今回は1対1の通信です。これをforkしたりすれば並列でメッセージの処理を行うことも可能ですね

サーバプログラム
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>


#define BUFFSIZE 256
#define ERR -1


int main(int argc, char *argv[])
{
    int socket_fd;//ソケット用のファイルディスクリプタ
    int accept_fd;
    struct sockaddr_un server;//サーバ構造体
    struct sockaddr_un client;//クライアント構造体
    int fromlen;
    char buf[BUFFSIZE];
    int message_len;

    if(argc != 2){
        printf("Usage: [command_name] [response message]\n");
        exit(1);
    }

    if( (socket_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == ERR){
        perror("server: socket");
        exit(1);
    }

    bzero((char * )&server, sizeof(server));
    //プロトコルファミリをunixに指定(UNIXドメイン)
    server.sun_family = PF_UNIX;

    bcopy("server_socket", server.sun_path, sizeof("server_socket"));

    unlink("server_socket");

    if(bind(socket_fd, (struct sockaddr *)&server, sizeof(server)) == ERR){
        perror("server: bind");
        exit(1);
    }

    if(listen(socket_fd, 5) == ERR){//5つのリクエストを受けます
        perror("server: listen");
        exit(1);
    }

    bzero((char *)&client, sizeof(client));
    fromlen = sizeof(client);

    if((accept_fd = accept(socket_fd, (struct sockaddr *)&client, &fromlen)) == ERR){
        perror("server: accept");
        exit(1);
    }

    printf("\nconnect request from: %s\n", client.sun_path);

    if(read(accept_fd, buf, BUFFSIZE) == ERR){
        perror("server: read");
        exit(1);
    }

  printf("\n<SERVER> message from client : %s\n", buf);

    message_len = strlen(argv[1]) + 1;
    if(write(accept_fd, argv[1], message_len) == ERR){
        //クライアントとのインターフェースとなるファイルディスクリプタを指定してメッセージのやり取り
        perror("server: write");
        exit(1);
    }

    close(accept_fd);
    close(socket_fd);

    exit(0);
}


クライアントプログラム
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>

#define BUFFSIZE 256
#define ERR -1

void main(int argc, char *argv[])
{
    int socket_fd;
    struct sockaddr_un server;
    struct hostent *hp;
    char buf[BUFFSIZE];
    int message_len;

    if(argc != 2){
        printf("Usage: [command] [message]\n");
        exit(1);
    }

    if( ( socket_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == ERR){
        perror("client: socket");
        exit(1);
    }

    bzero((char *)&server, sizeof(server));
    server.sun_family = PF_UNIX;
    bcopy("server_socket", server.sun_path, sizeof("server_socket"));

    if(connect(socket_fd, (struct sockaddr *)&server, sizeof(server)) == ERR){
        perror("client: connect");
        exit(1);
    }

    message_len = strlen(argv[1]) + 1;

    if(write(socket_fd, argv[1], message_len) == ERR){
        perror("client: write");
        exit(1);
    }

    if(read(socket_fd, buf, BUFFSIZE) == ERR){
        perror("client: read");
        exit(1);
    }

    printf("\n<CLIENT>message from server : %s\n\n", buf);

    close(socket_fd);

    exit(0);
}


作ってみて

「ソケット」という「ファイル」に対して、read,writeというシステムコールが使えた(Unixはすべてをファイルとして扱う思想そのもの)

これは通常のファイルに読み書きする感覚で通信相手のプロセスにデータを送ることができるということ。

次はIPを使ったINETドメインについて書きます。
テーマ : コンピュータ関連
ジャンル : コンピュータ

Tag:C/C++  Trackback:0 comment:0 

【C】SharedObject作成メモ

Cで作ったプログラムをSharedObject(共有オブジェクト)として認識させるときのメモです

【コマンドログ】
gcc -fPIC -c libtest.c -o libtest.lo
gcc -shared -Wl,-soname,libtest.so libtest.lo -o libtest.so
ldconfig -n .
gcc -c test.c
gcc -o test -L. -ltest test.o
LD_LIBRARY_PATH=. ./test

ソースのメモです。
libtest.h
void test();

libtest.c
#include
#include "libtest.h"

void test(){
printf("Hello!\n");
}

ライブラリを使う側
test.c
#include "libtest.h"

int main(void){
test();
return 0;
}
テーマ : UNIX/Linux
ジャンル : コンピュータ

Tag:C/C++  Trackback:0 comment:0 

プロフィール

6rats

Author:6rats
こんにちは、ITベンチャーで働くエンジニアです
主に自分の周りで起きた技術的なことをメモとして書き残して行きます。
Android以外にもRuby/Ruby on RailsやFuelPHPなどなどたまにやります。基本的なスタンスとしては興味があるもしくは必要になったらいろんなことにチャレンジします。
最近はiOSアプリ開発を始めています。

購読
follow us in feedly
個人プロダクト

Androidアプリ

Twitterクライアント

Webアプリケーション

EcPriceWatch(Amazon価格の推移を計測、最安値を知らせるサービス)
Google AdSense
ブログ村
にほんブログ村 IT技術ブログへ
にほんブログ村
ブロとも申請フォーム

この人とブロともになる

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。