Last active
August 29, 2015 14:16
-
-
Save hiroshiro/88a9dc9997a6ebd0f916 to your computer and use it in GitHub Desktop.
LinuxネットワーキングプログラミングバイブルTCP/IPプログラミング入門Chapter03 getaddinf()を利用しないserver_socket()IP4
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 <sys/param.h> | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <netdb.h> | |
#include <ctype.h> | |
#include <errno.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sysexits.h> | |
#include <unistd.h> | |
/* send_recv_loopの定義 */ | |
void send_recv_loop(int); | |
/* サーバーソケットの準備 */ | |
int server_socket(const char *portnm) | |
{ | |
struct sockaddr_in my; | |
int soc, portno, opt; | |
socklen_t opt_len; | |
struct servent *se; | |
/* アドレス情報を0クリア */ | |
(void) memset(&my, 0, sizeof(my)); | |
my.sin_family = AF_INET; | |
my.sin_addr.s_addr = htonl(INADDR_ANY); | |
/* ポート番号の決定 */ | |
if (isdigit(portnm[0])) { | |
/* 先頭が数字 */ | |
if (( portno = atoi(portnm)) <= 0) { | |
/* 数値化するとゼロ以下 */ | |
(void) fprintf(stderr, "bad port no\n"); | |
return (-1); | |
} | |
my.sin_port = htons(portno); | |
} else { | |
if ((se = getservbyname(portnm, "tcp")) == NULL) { | |
/* サービスに見つからない */ | |
(void) fprintf(stderr, "getservent():error\n"); | |
return (-1); | |
} else { | |
/* サービス見つかった:該当ポート番号 */ | |
my.sin_port = se->s_port; | |
} | |
} | |
(void) fprintf(stderr, "port=%d\n", ntohs(my.sin_port)); | |
/* ソケットの生成 */ | |
if ((soc = socket(PF_INET, SOCK_STREAM, 0)) == -1) { | |
perror("socket"); | |
return (-1); | |
} | |
/* ソケットオプション(再利用フラグ)設定 */ | |
opt = 1; | |
opt_len = sizeof(opt); | |
if (setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &opt, opt_len) == -1) { | |
perror("setsockopt"); | |
(void) close(soc); | |
return (-1); | |
} | |
/* ソケットにアドレスを指定 */ | |
if (bind(soc, (struct sockaddr *) &my, sizeof(my)) == -1) { | |
perror("bind"); | |
(void) close(soc); | |
return (-1); | |
} | |
/* アクセスバッグログの指定 */ | |
if (listen(soc, SOMAXCONN) == -1) { | |
perror("listen"); | |
(void) close(soc); | |
return (-1); | |
} | |
return (soc); | |
} | |
/* アクセプトループ */ | |
void accept_loop(int soc) | |
{ | |
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; | |
struct sockaddr_storage from; | |
int acc; | |
socklen_t len; | |
for(;;){ | |
len = (socklen_t) sizeof(from); | |
/* 接続受付 */ | |
if (( acc = accept(soc, (struct sockaddr *) &from, &len)) == -1) { | |
if (errno != EINTR) { | |
perror("accept"); | |
} | |
} else { | |
(void) getnameinfo((struct sockaddr *) &from, len, | |
hbuf, sizeof(hbuf), | |
sbuf, sizeof(sbuf), | |
NI_NUMERICHOST | NI_NUMERICSERV); | |
(void) fprintf(stderr, "accept:%s:%s\n",hbuf, sbuf); | |
/* 送受信ループ */ | |
send_recv_loop(acc); | |
/* アクセプトソケットクローズ */ | |
(void) close(acc); | |
acc = 0; | |
} | |
} | |
} | |
/* サイズ指定文字列連結 */ | |
size_t mystrlcat(char *dst, const char *src, size_t size) | |
{ | |
const char *ps; | |
char *pd, *pde; | |
size_t dlen, lest; | |
for (pd = dst, lest = size; *pd != '\0' && lest != 0; pd++, lest--); | |
dlen = pd - dst; | |
if (size - dlen == 0) { | |
return (dlen + strlen(src)); | |
} | |
pde = dst + size - 1; | |
for (ps = src; *ps != '\0' && pd < pde; pd++, ps++) { | |
*pd = *ps; | |
} | |
for (; pd <= pde; pd++) { | |
*pd = '\0'; | |
} | |
while (*ps++); | |
return (dlen = (ps - src - 1)); | |
} | |
/* 送受信ループ */ | |
void send_recv_loop(int acc) | |
{ | |
char buf[512], *ptr; | |
ssize_t len; | |
for (;;) { | |
/* 受信 */ | |
if ((len = recv(acc, buf ,sizeof(buf), 0)) == -1) { | |
/* エラー */ | |
perror("recv"); | |
break; | |
} | |
if (len == 0) { | |
(void) fprintf(stderr, "recv:EOF\n"); | |
break; | |
} | |
/* 文字列化・表示 */ | |
buf[len] = '\0'; | |
if((ptr = strpbrk(buf, "\r\n")) != NULL) { | |
*ptr = '\0'; | |
} | |
(void) fprintf(stderr, "[client]%s\n", buf); | |
/* 応答文字列作成 */ | |
(void) mystrlcat(buf, ":OK\r\n", sizeof(buf)); | |
len = (ssize_t) strlen(buf); | |
/* 反応 */ | |
if ((len = send(acc, buf, (size_t) len, 0)) == -1) { | |
/* エラー */ | |
perror("send"); | |
break; | |
} | |
} | |
} | |
int main(int argc, const char *argv[]) | |
{ | |
int soc; | |
/* 引数にポート番号がしていされているか? */ | |
if (argc <= 1) { | |
(void) fprintf(stderr, "server port\n"); | |
return (EX_USAGE); | |
} | |
/* サーバーソケットの準備 */ | |
if ((soc = server_socket(argv[1])) == -1) { | |
(void) fprintf(stderr, "server_socket(%s):error\n", argv[1]); | |
return (EX_UNAVAILABLE); | |
} | |
(void) fprintf(stderr, "ready for accept\n"); | |
/* アクセプトループ */ | |
accept_loop(soc); | |
/* ソケットクローズ */ | |
(void) close(soc); | |
return (EX_OK); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment