#include <signal.h> struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGPIPE, &sa, 0);
2012/08/01
Ignore SIGPIPE in socket programming
通常在寫 socket programming 時,系統對一個 invalid fd (file descriptor) 做寫入時會讓系統丟出 SIGPIPE 的 signal,為了避免程式被中斷,通常都會 ignore 它。
2011/07/12
在iPhone上建立HTTP連線(GET/POST)
HTTP Get
Create requestNSString *str = @"http://my_server/get.php?name=brian&gender=male"; NSString *str_enc = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *url = [[NSURL URLWithString:str_enc] retain]; NSURLRequest *req = [NSURLRequest requestWithURL:url]; NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
Prepare delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; - (void)connectionDidFinishLoading:(NSURLConnection *)connection; - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
HTTP Post
NSString *content = @"name=brian&gender=male"; NSData *postData = [content dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; [request setURL:[NSURL URLWithString:@"http://my_server/post.php"]]; [request setHTTPMethod:@"POST"]; /* Header */ [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; /* Content */ [request setHTTPBody:postData]; connect = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // 跟GET一樣設定4組delegate去接response
參考資料
2011/06/20
HTTP server over libevent - sample code (2)
加入一些parse的function,可以得到request的method、URI、header、body、path
Compile and run
try to send a request to server...
#include#include #include #include #include #define SVR_IP "127.0.0.1" #define SVR_PORT 8080 void dump_cb (struct evhttp_request *req, void *arg) { const char *uri; struct evkeyvalq *headers; struct evkeyval *header; struct evbuffer *evbuf; struct evhttp_uri *ev_uri; /* Get method */ switch (evhttp_request_get_command(req)) { case EVHTTP_REQ_GET: printf("Request method=[GET]\n"); break; case EVHTTP_REQ_POST: printf("Request method=[POST]\n"); break; default: printf("Request method=[others]\n"); break; } /* Get path */ uri = evhttp_request_get_uri(req); printf("Request uri=[%s]\n", uri); /* Get header */ printf("Headers:\n"); headers = evhttp_request_get_input_headers(req); for (header = headers->tqh_first; header; header = header->next.tqe_next) { printf(" %s: %s\n", header->key, header->value); } /* Get body */ evbuf = evhttp_request_get_input_buffer(req); printf("Body:\n"); while (evbuffer_get_length(evbuf)) { int size; char buf[128]; memset(buf, 0, sizeof(buf)); size = evbuffer_remove(evbuf, buf, sizeof(buf) - 1); printf(" %s\n", buf); } /* */ ev_uri = evhttp_uri_parse(uri); if (ev_uri) { const char *path; char *decoded_path; path = evhttp_uri_get_path(ev_uri); decoded_path = evhttp_uridecode(path, 0, NULL); printf("Request path=[%s]\n", decoded_path); /* Free resource */ free(decoded_path); evhttp_uri_free(ev_uri); } /* Response */ evhttp_send_reply(req, HTTP_OK, "OK", NULL); } int main (int argc, char **argv) { struct event_base *evbase; struct evhttp *evhttp; /* Init event base */ if ((evbase = event_base_new()) == NULL) { printf("event_base_new() failed\n"); return -1; } /* Init evhttp */ if ((evhttp = evhttp_new(evbase)) == NULL) { printf("evhttp_new() failed\n"); return -1; } /* Set server IP, port */ if (evhttp_bind_socket(evhttp, SVR_IP, SVR_PORT) == -1) { printf("evhttp_bind_socket() failed\n"); return -1; } else { printf("Listening on [%s:%d]\n", SVR_IP, SVR_PORT); } /* Set timeout */ evhttp_set_timeout(evhttp, 10); /* Set a callback for default path */ evhttp_set_gencb(evhttp, dump_cb, NULL); /* Enter event loop */ event_base_dispatch(evbase); /* Free resource */ evhttp_free(evhttp); event_base_free(evbase); return 0; }
Compile and run
$ gcc -g -Wall -o httpd httpd.c -levent -I/opt/libevent-2.0.12-stable/include/ -L/opt/libevent-2.0.12-stable/lib/ $ LD_LIBRARY_PATH=/opt/libevent-2.0.12-stable/lib ./httpd Listening on [127.0.0.1:8080] Request method=[GET] Request uri=[/test.php?name=kevin&sex=male] Headers: User-Agent: Wget/1.11.4 Red Hat modified Accept: */* Host: 127.0.0.1:8080 Connection: Keep-Alive Body: Request path=[/test.php] Request method=[POST] Request uri=[/test.php] Headers: User-Agent: Wget/1.11.4 Red Hat modified Accept: */* Host: 127.0.0.1:8080 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded Content-Length: 19 Body: name=sylar&sex=male Request path=[/test.php]
try to send a request to server...
# Get $wget -q -O - 'http://127.0.0.1:8080/test.php?name=sylar&sex=male' # Post $wget -q -O - --post-data='name=sylar&sex=male' http://127.0.0.1:8080/test.php
2011/06/17
HTTP server over libevent - sample code (1)
使用libevent HTTP API寫一個簡易的server。
#includeCompile and run#include #include #define SVR_IP "127.0.0.1" #define SVR_PORT 8080 void specific_cb (struct evhttp_request *req, void *arg) { struct evbuffer *evbuf; if ((evbuf = evbuffer_new()) == NULL) { printf("evbuffer_new() failed"); evhttp_send_reply(req, HTTP_INTERNAL, "Internal error", NULL); return; } /* Body */ evbuffer_add_printf(evbuf, "It's work!"); /* Response */ evhttp_send_reply(req, HTTP_OK, "OK", evbuf); /* Free resource */ evbuffer_free(evbuf); } void generic_cb (struct evhttp_request *req, void *arg) { /* Response */ evhttp_send_reply(req, HTTP_NOTFOUND, "Not found", NULL); } int main (int argc, char **argv) { struct event_base *evbase; struct evhttp *evhttp; /* Init event base */ if ((evbase = event_base_new()) == NULL) { printf("event_base_new() failed\n"); return -1; } /* Init evhttp */ if ((evhttp = evhttp_new(evbase)) == NULL) { printf("evhttp_new() failed\n"); return -1; } /* Set server IP, port */ if (evhttp_bind_socket(evhttp, SVR_IP, SVR_PORT) == -1) { printf("evhttp_bind_socket() failed\n"); return -1; } else { printf("Listening on [%s:%d]\n", SVR_IP, SVR_PORT); } /* Set a callback for specific path */ if (evhttp_set_cb(evhttp, "/test", specific_cb, NULL) < 0) { printf("evhttp_set_cb() failed\n"); return -1; } /* Set a callback for default path */ evhttp_set_gencb(evhttp, generic_cb, NULL); /* Enter event loop */ event_base_dispatch(evbase); /* Free resource */ evhttp_free(evhttp); event_base_free(evbase); return 0; }
$ gcc -g -Wall -o httpd httpd.c -levent -I/opt/libevent-2.0.12-stable/include/ -L/opt/libevent-2.0.12-stable/lib/ $ LD_LIBRARY_PATH=/opt/libevent-2.0.12-stable/lib ./httpd Listening on [127.0.0.1:8080]try to send a request to server...
$ wget -q -O - http://127.0.0.1:8080/test $ wget -S -O - http://127.0.0.1:8080/xxx不知道為什麼我用2.0.10-stable版本跑會有下列warning,用2.0.12-stable就沒問題了。
[warn] evhttp_connection_base_new: bufferevent_new failed: No such file or directory [warn] evhttp_get_request: cannot get connection on 9: No such file or directory
2011/06/16
C socket client in Linux - sample code
Sample code
#include#include #include #include #include #include #include #include #define LOCAL_IP "127.0.0.1" #define LOCAL_PORT 5678 #define SVR_IP "127.0.0.1" #define SVR_PORT 8080 #define BUF_SIZE 1024 #define MESSAGE "hello" int main (int argc, char **argv) { struct sockaddr_in local_addr, server_addr; socklen_t len; int sock_fd; char buff[BUF_SIZE]; int recv_len; len = sizeof(struct sockaddr_in); /* Set local address (In general, we don't care local address) */ memset(&local_addr, 0, sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = inet_addr(LOCAL_IP); local_addr.sin_port = htons(LOCAL_PORT); /* Set server address */ memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(SVR_IP); server_addr.sin_port = htons(SVR_PORT); /* Create endpoint */ if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket()"); return -1; } else { printf("sock_fd=[%d]\n", sock_fd); } /* Bind */ if (bind(sock_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1) { perror("bind()"); return -1; } else { printf("bind [%s:%u] success\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port)); } /* Connect */ if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("connect()"); return -1; } else { printf("connect to [%s:%u] success\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); } /* Send */ send(sock_fd, MESSAGE, strlen(MESSAGE), 0); /* Receive */ memset(buff, 0, sizeof(buff)); recv_len = recv(sock_fd, buff, sizeof(buff), 0); if (recv_len == -1) { perror("recv()"); return -1; } else if (recv_len == 0) { printf("Client disconnect\n"); } else { printf("Receive: len=[%d] msg=[%s]\n", recv_len, buff); } return 0; }
2011/06/15
C socket server in Linux - sample code
長期用libevent來implement socket program,都快忘了一般select的用法了,寫了一個echo server
供各位參考。
不過有一點我還是不太懂,為何fd_set要copy一份起來,是因為fd_set 經過select function後就無效了嗎?我試過只用一個fd_set,果真只能接收到第一個request,除非每次select前重新把所有的fd做FD_SET()。
Select的用法可以參考:石頭閒語:select() - I/O Multiplexer
供各位參考。
不過有一點我還是不太懂,為何fd_set要copy一份起來,是因為fd_set 經過select function後就無效了嗎?我試過只用一個fd_set,果真只能接收到第一個request,除非每次select前重新把所有的fd做FD_SET()。
Select的用法可以參考:石頭閒語:select() - I/O Multiplexer
#include#include #include #include #include #include #include #include #define SVR_IP "127.0.0.1" #define SVR_PORT 8080 #define BUF_SIZE 1024 int main (int argc, char **argv) { struct sockaddr_in server_addr; socklen_t len; fd_set active_fd_set; int sock_fd; int max_fd; int flag = 1; char buff[BUF_SIZE]; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(SVR_IP); server_addr.sin_port = htons(SVR_PORT); len = sizeof(struct sockaddr_in); /* Create endpoint */ if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket()"); return -1; } else { printf("sock_fd=[%d]\n", sock_fd); } /* Set socket option */ if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) < 0) { perror("setsockopt()"); return -1; } /* Bind */ if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind()"); return -1; } else { printf("bind [%s:%u] success\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port)); } /* Listen */ if (listen(sock_fd, 128) == -1) { perror("listen()"); return -1; } FD_ZERO(&active_fd_set); FD_SET(sock_fd, &active_fd_set); max_fd = sock_fd; while (1) { int ret; struct timeval tv; fd_set read_fds; /* Set timeout */ tv.tv_sec = 2; tv.tv_usec = 0; /* Copy fd set */ read_fds = active_fd_set; ret = select(max_fd + 1, &read_fds, NULL, NULL, &tv); if (ret == -1) { perror("select()"); return -1; } else if (ret == 0) { printf("select timeout\n"); continue; } else { int i; /* Service all sockets */ for (i = 0; i < FD_SETSIZE; i++) { if (FD_ISSET(i, &read_fds)) { if (i == sock_fd) { /* Connection request on original socket. */ struct sockaddr_in client_addr; int new_fd; /* Accept */ new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &len); if (new_fd == -1) { perror("accept()"); return -1; } else { printf("Accpet client come from [%s:%u] by fd [%d]\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), new_fd); /* Add to fd set */ FD_SET(new_fd, &active_fd_set); if (new_fd > max_fd) max_fd = new_fd; } } else { /* Data arriving on an already-connected socket */ int recv_len; /* Receive */ memset(buff, 0, sizeof(buff)); recv_len = recv(i, buff, sizeof(buff), 0); if (recv_len == -1) { perror("recv()"); return -1; } else if (recv_len == 0) { printf("Client disconnect\n"); } else { printf("Receive: len=[%d] msg=[%s]\n", recv_len, buff); /* Send (In fact we should determine when it can be written)*/ send(i, buff, recv_len, 0); } /* Clean up */ close(i); FD_CLR(i, &active_fd_set); } } // end of if } //end of for } // end of if } // end of while return 0; }
2011/06/08
Get IPv4 address from sockaddr or socket
(sock_fd is a socket)
sockaddr_in addr_in;
int len = sizeof(sockaddr_in);
/* Get sockaddr_in structure information from socket */
getsockname(sock_fd, (sockaddr *)&addr_in, (socklen_t *)&len);
/* Get address from sockaddr_in */
printf("IP=[%s] port=[%d]\n", inet_ntoa(addr_in.sin_addr), addr_in.sin_port);
2011/05/19
UDP server over libevent - sample code
基本的sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#include <event2/listener.h>
#define SVR_IP "127.0.0.1"
#define SVR_PORT 10000
#define BUF_SIZE 1024
void read_cb(int fd, short event, void *arg) {
char buf[BUF_SIZE];
int len;
int size = sizeof(struct sockaddr);
struct sockaddr_in client_addr;
memset(buf, 0, sizeof(buf));
len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &size);
if (len == -1) {
perror("recvfrom()");
} else if (len == 0) {
printf("Connection Closed\n");
} else {
printf("Read: len [%d] - content [%s]\n", len, buf);
/* Echo */
sendto(fd, buf, len, 0, (struct sockaddr *)&client_addr, size);
}
}
int bind_socket(struct event *ev) {
int sock_fd;
int flag = 1;
struct sockaddr_in sin;
/* Create endpoint */
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket()");
return -1;
}
/* Set socket option */
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)) < 0) {
perror("setsockopt()");
return 1;
}
/* Set IP, port */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(SVR_IP);
sin.sin_port = htons(SVR_PORT);
/* Bind */
if (bind(sock_fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0) {
perror("bind()");
return -1;
} else {
printf("bind() success - [%s] [%u]\n", SVR_IP, SVR_PORT);
}
/* Init one event and add to active events */
event_set(ev, sock_fd, EV_READ | EV_PERSIST, &read_cb, NULL);
if (event_add(ev, NULL) == -1) {
printf("event_add() failed\n");
}
return 0;
}
int main(void) {
struct event ev;
/* Init. event */
if (event_init() == NULL) {
printf("event_init() failed\n");
return -1;
}
/* Bind socket */
if (bind_socket(&ev) != 0) {
printf("bind_socket() failed\n");
return -1;
}
/* Enter event loop */
event_dispatch();
return 0;
}
訂閱:
文章 (Atom)