$ gcc -g -Wall -I /path/to/libuv/include /path/to/libuv/uv.a -framework CoreServices server.c -o server
$ gcc -g -Wall -I /path/to/libuv/include /path/to/libuv/uv.a -framework CoreServices client.c -o client
-
-
Save ximik777/0aae25b0f827653a1489b49cd54e1046 to your computer and use it in GitHub Desktop.
libuv TCP server/client sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <uv.h> | |
#define log(x) printf("%s\n", x); | |
uv_loop_t *loop; | |
void on_connect(uv_connect_t *req, int status); | |
void on_write_end(uv_write_t *req, int status); | |
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size); | |
void echo_read(uv_stream_t *server, ssize_t nread, uv_buf_t buf); | |
// サーバからのレスポンスを表示 | |
void echo_read(uv_stream_t *server, ssize_t nread, uv_buf_t buf) { | |
if (nread == -1) { | |
fprintf(stderr, "error echo_read"); | |
return; | |
} | |
// 結果を buf から取得して表示 | |
printf("result: %s\n", buf.base); | |
} | |
// suggeseted_size で渡された領域を確保 | |
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size) { | |
// 読み込みのためのバッファを、サジェストされたサイズで確保 | |
return uv_buf_init((char*) malloc(suggested_size), suggested_size); | |
} | |
// サーバへデータ送信後, サーバからのレスポンスを読み込む | |
void on_write_end(uv_write_t *req, int status) { | |
if (status == -1) { | |
fprintf(stderr, "error on_write_end"); | |
return; | |
} | |
// 書き込みが終わったら、すぐに読み込みを開始 | |
uv_read_start(req->handle, alloc_buffer, echo_read); | |
} | |
// サーバとの接続を確立後, サーバに文字列を送信 | |
void on_connect(uv_connect_t *req, int status) { | |
if (status == -1) { | |
fprintf(stderr, "error on_write_end"); | |
return; | |
} | |
// 送信メッセージを登録 | |
char *message = "hello.txt"; | |
int len = strlen(message); | |
/** これだとセグフォ | |
* uv_buf_t buf[1]; | |
* buf[0].len = len; | |
* buf[0].base = message; | |
*/ | |
// 送信データ用のバッファ | |
char buffer[100]; | |
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer)); | |
// 送信データを載せる | |
buf.len = len; | |
buf.base = message; | |
// ハンドルを取得 | |
uv_stream_t* tcp = req->handle; | |
// 書き込み用構造体 | |
uv_write_t write_req; | |
int buf_count = 1; | |
// 書き込み | |
uv_write(&write_req, tcp, &buf, buf_count, on_write_end); | |
} | |
int main(void) { | |
// loop 生成 | |
loop = uv_default_loop(); | |
// Network I/O の構造体 | |
uv_tcp_t client; | |
// loop への登録 | |
uv_tcp_init(loop, &client); | |
// アドレスの取得 | |
struct sockaddr_in req_addr = uv_ip4_addr("127.0.0.1", 7000); | |
// TCP コネクション用の構造体 | |
uv_connect_t connect_req; | |
// 接続 | |
uv_tcp_connect(&connect_req, &client, req_addr, on_connect); | |
// ループを開始 | |
return uv_run(loop); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hello from file on server! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <uv.h> | |
// uv_handle_t > uv_stream_t > uv_tcp_t | |
const int backlog = 128; | |
const int buffer_size = 1024; | |
uv_fs_t open_req; | |
uv_fs_t read_req; | |
uv_tcp_t *client; // 接続してきたクライアント(取り回しを楽にするため | |
void on_new_connection(uv_stream_t *server, int status); | |
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size); | |
void on_client_read(uv_stream_t *client, ssize_t nread, uv_buf_t buf); | |
void on_client_write(uv_write_t *req, int status); | |
void on_file_open(uv_fs_t *req); | |
void on_file_read(uv_fs_t *req); | |
// クライアントと接続後, クライアントからのデータを読み込む | |
void on_new_connection(uv_stream_t *server, int status) { | |
if (status == -1) { | |
fprintf(stderr, "error on_new_connection"); | |
uv_close((uv_handle_t*) client, NULL); | |
return; | |
} | |
// クライアントを保持するためのメモリを確保 | |
client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); | |
// loop への登録 | |
uv_tcp_init(uv_default_loop(), client); | |
// accept | |
int result = uv_accept(server, (uv_stream_t*) client); | |
if (result == 0) { // success | |
// クライアントからのデータを読みだして、alloc_buffer で確保した領域に書き込み、callback を呼ぶ | |
uv_read_start((uv_stream_t*) client, alloc_buffer, on_client_read); | |
} else { // error | |
uv_close((uv_handle_t*) client, NULL); | |
} | |
} | |
// suggeseted_size で渡された領域を確保 | |
uv_buf_t alloc_buffer(uv_handle_t *handle, size_t suggested_size) { | |
return uv_buf_init((char*) malloc(suggested_size), suggested_size); | |
} | |
// tcp クライアントから受け取ったファイル名を開く | |
void on_client_read(uv_stream_t *_client, ssize_t nread, uv_buf_t buf) { | |
if (nread == -1) { | |
fprintf(stderr, "error on_client_read"); | |
uv_close((uv_handle_t*) client, NULL); | |
return; | |
} | |
// クライアントから受け取ったデータ | |
// データは buf.base に格納されている。 | |
char *filename = buf.base; | |
int mode = 0; | |
// ファイルを開く | |
uv_fs_open(uv_default_loop(), &open_req, filename, O_RDONLY, mode, on_file_open); | |
} | |
// client に返したあとの後片付け | |
void on_client_write(uv_write_t *req, int status) { | |
if (status == -1) { | |
fprintf(stderr, "error on_client_write"); | |
uv_close((uv_handle_t*) client, NULL); | |
return; | |
} | |
// 開放 | |
free(req); | |
// ここで開放するためにつけておいた。 | |
char *buffer = (char*) req->data; | |
free(buffer); | |
// tcp connection を閉じる | |
uv_close((uv_handle_t*) client, NULL); | |
} | |
// 開いたファイルの内容を読む | |
void on_file_open(uv_fs_t *req) { | |
if (req->result == -1) { | |
fprintf(stderr, "error on_file_read"); | |
uv_close((uv_handle_t*) client, NULL); | |
return; | |
} | |
// ファイルから読み込んだデータを入れるバッファ | |
char *buffer = (char *) malloc(sizeof(char) * buffer_size); | |
// 読み込みを登録,書き込みのバッファを指定 | |
int offset = -1; | |
// data フィールドに入れてコールバック関数に渡す | |
read_req.data = (void*) buffer; | |
// ここは非同期コールバック | |
uv_fs_read(uv_default_loop(), &read_req, req->result, buffer, sizeof(char) * buffer_size, offset, on_file_read); | |
// read を登録したら開放 | |
uv_fs_req_cleanup(req); | |
} | |
// ファイルの内容をクライアントに返す | |
void on_file_read(uv_fs_t *req) { | |
if (req->result < 0) { | |
fprintf(stderr, "error on_file_read"); | |
uv_close((uv_handle_t*) client, NULL); | |
} else if (req->result == 0) { // 読み終わったら閉じる | |
uv_fs_t close_req; | |
uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL); | |
uv_close((uv_handle_t*) client, NULL); | |
} else { // 読み込んだ内容をクライアントに返す | |
// 書き込み用の領域確保 | |
uv_write_t *write_req = (uv_write_t *) malloc(sizeof(uv_write_t)); | |
// クライアントに返す内容 | |
// req->data に入っているバッファのポインタより読み込む | |
char *message = (char*) req->data; | |
// uv_write に使う uv_buf_t の準備 | |
uv_buf_t buf = uv_buf_init(message, sizeof(message)); | |
buf.len = req->result; | |
buf.base = message; | |
int buf_count = 1; | |
// on_client_write 内で開放できるように、 | |
// ポインタを格納して渡す。 | |
write_req->data = (void*) message; | |
// client に buf を書き込む | |
uv_write(write_req, (uv_stream_t*) client, &buf, buf_count, on_client_write); | |
} | |
// 同期で開放 | |
uv_fs_req_cleanup(req); | |
} | |
int main(void) { | |
// Network I/O の構造体 | |
uv_tcp_t server; | |
// loop への登録 | |
uv_tcp_init(uv_default_loop(), &server); | |
// アドレスの取得 | |
struct sockaddr_in bind_addr = uv_ip4_addr("0.0.0.0", 7000); | |
// bind | |
uv_tcp_bind(&server, bind_addr); | |
// uv_stream_t: uv_handle_t のサブクラス uv_tcp_t の親 | |
// listen | |
int r = uv_listen((uv_stream_t*) &server, backlog, on_new_connection); | |
if (r) { | |
// エラー処理 | |
fprintf(stderr, "error uv_listen"); | |
return 1; | |
} | |
// ループ開始 | |
uv_run(uv_default_loop()); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment