WinSock2+FILE I/Oを利用したネットワークサーバのサンプル
Last active
September 7, 2018 18:55
-
-
Save kosh04/3772420 to your computer and use it in GitHub Desktop.
WinSock2+FILE I/Oを利用したネットワークサーバのサンプル
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 "server.h" | |
#include <stdio.h> | |
#include <string.h> | |
#include <ctype.h> | |
#define RCVBUFSIZE 16 | |
char *upcase(char *s) { | |
for (char *p=s; *p; ++p) | |
*p = toupper(*p); | |
return s; | |
} | |
char *chomp(char *s) { | |
char *eol = strpbrk(s, "\n"); | |
if (eol) *eol = '\0'; | |
return s; | |
} | |
void execute_echo(FILE *r, FILE *w) { | |
char line[RCVBUFSIZE+1] = {0}; | |
while (fgets(line, sizeof(line), r) != NULL) { | |
//fprintf(w, "%s", upcase(line)); | |
size_t len = strlen(line); | |
size_t n = fwrite(upcase(line), 1, len, w); | |
if (n < len) { | |
debug("write %"PRIdSIZE" byte, but expect %"PRIdSIZE" byte: '%s\\n'\n", n, len, chomp(line)); | |
} | |
} | |
} | |
int main() { | |
start_server("1234", execute_echo); | |
return 0; | |
} |
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
/** | |
* http-server.c | |
* | |
* Usage: | |
* | |
* [server]$ make http-server | |
* [server]$ ./http-server 4711 | |
* [client]$ curl -v localhost 4711 | |
*/ | |
#include "server.h" | |
#include <stdio.h> | |
#include <string.h> | |
#define RCVBUFSIZE 255 | |
void usage(char *progname) | |
{ | |
fprintf(stderr, "Usage: %s PORT\n", progname); | |
} | |
void execute_http_request(FILE *r, FILE *w) | |
{ | |
char buf[RCVBUFSIZE + 1] = {0}; | |
// read headers (ignored) | |
while (fgets(buf, RCVBUFSIZE + 1, r) != NULL) { | |
if (strcmp(buf, "\r\n") == 0 || strcmp(buf, "\n") == 0) break; | |
debug("recv: [%s]\r\n", buf); | |
} | |
char contents[] = "Hello, world!"; | |
fprintf(w, "HTTP/1.0 200 OK\r\n"); | |
fprintf(w, "Server: simple httpd 0.1\r\n"); | |
fprintf(w, "Content-Type: text/plain\r\n"); | |
fprintf(w, "Content-Length: %"PRIdSIZE"\r\n", strlen(contents)); | |
fprintf(w, "\r\n"); | |
fprintf(w, "%s", contents); | |
return; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 2) { | |
usage(argv[0]); | |
return 1; | |
} | |
char *service = argv[1]; | |
start_server(service, execute_http_request); | |
return 0; | |
} |
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
ifeq ($(OS),Windows_NT) | |
CC = gcc | |
endif | |
TARGET := http-server echo-server | |
CFLAGS := -std=gnu99 -Wall -Werror -g3 -O0 \ | |
$(if $(findstring MINGW,$(MSYSTEM)),-Wno-pedantic-ms-format) | |
LDLIBS := $(if $(findstring MINGW,$(MSYSTEM)),-lws2_32) | |
default: $(TARGET) | |
http-server: http-server.o server.o | |
echo-server: echo-server.o server.o | |
clean: | |
$(RM) *.o $(TARGET) |
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
// server.c | |
#include "server.h" | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifdef _WIN32 | |
#define WIN32_LEAN_AND_MEAN | |
#include <winsock2.h> | |
#include <ws2tcpip.h> | |
#include <mswsock.h> | |
#include <io.h> // _open_osfhandle | |
typedef int socklen_t; | |
#else // unix | |
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <arpa/inet.h> | |
#include <netdb.h> | |
#include <unistd.h> | |
typedef int SOCKET; | |
#define closesocket close | |
#define SOCKET_ERROR (-1) | |
#define INVALID_SOCKET ((SOCKET)(~0)) | |
#endif | |
#define MAX_BACKLOG 5 | |
void socket_startup() | |
{ | |
#ifdef _WIN32 | |
WSADATA wsaData; | |
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { | |
WSACleanup(); | |
exit(EXIT_FAILURE); | |
} | |
int opt = SO_SYNCHRONOUS_NONALERT; | |
setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, sizeof(opt)); | |
#endif | |
} | |
void socket_cleanup() | |
{ | |
#ifdef _WIN32 | |
WSACleanup(); | |
#endif | |
} | |
static char *sockaddr_info(const struct sockaddr *sa) | |
{ | |
static char buf[NI_MAXHOST + NI_MAXSERV + 2] = {0}; // "HOST:PORT\0" | |
char hostname[NI_MAXHOST] = {0}; | |
char servname[NI_MAXSERV] = {0}; | |
size_t addrlen; | |
int rc; | |
if (sa->sa_family == AF_INET) | |
addrlen = sizeof(struct sockaddr_in); | |
else // AF_INET6 | |
addrlen = sizeof(struct sockaddr_in6); | |
rc = getnameinfo(sa, addrlen, | |
hostname, sizeof(hostname), | |
servname, sizeof(servname), | |
NI_NUMERICHOST | NI_NUMERICSERV); | |
if (rc != 0) { | |
debug("getnameinfo: %s\n", gai_strerror(rc)); | |
return NULL; | |
} | |
snprintf(buf, sizeof(buf), "%s:%s", hostname, servname); | |
return buf; | |
} | |
int tcp_listen(const char *nodename, const char *service) | |
{ | |
struct addrinfo hints; | |
struct addrinfo *ans = NULL; | |
int sockfd, err; | |
memset(&hints, 0, sizeof(hints)); | |
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ | |
hints.ai_flags = AI_PASSIVE; | |
hints.ai_socktype = SOCK_STREAM; | |
err = getaddrinfo(nodename, service, &hints, &ans); | |
if (err != 0) { | |
debug("getaddrinfo: %s\n", gai_strerror(err)); | |
return -1; | |
} | |
/* #ifdef _WIN32 | |
* sockfd = WSASocket(ans->ai_family, ans->ai_socktype, ans->ai_protocol, NULL, 0, 0); | |
* #else */ | |
sockfd = socket(ans->ai_family, ans->ai_socktype, ans->ai_protocol); | |
//#endif | |
if (sockfd == -1) { | |
perror("socket"); | |
return -1; | |
} | |
int yes = 1; | |
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof(yes)); | |
if (bind(sockfd, ans->ai_addr, ans->ai_addrlen) == -1) { | |
perror("bind"); | |
return -1; | |
} | |
if (listen(sockfd, MAX_BACKLOG) == -1) { | |
perror("listen"); | |
return -1; | |
} | |
debug("listening %s.\n", sockaddr_info(ans->ai_addr)); | |
freeaddrinfo(ans); | |
return sockfd; | |
} | |
void start_server(char *service, void (*request_handler)(FILE *, FILE *)) | |
{ | |
socket_startup(); | |
int listen_socket = tcp_listen(NULL, service); | |
if (listen_socket == INVALID_SOCKET) { | |
return; | |
} | |
for (;;) { | |
struct sockaddr_storage from; | |
socklen_t fromlen = sizeof(from); | |
int accept_socket = accept(listen_socket, (struct sockaddr *)&from, &fromlen); | |
if (accept_socket == INVALID_SOCKET) { | |
perror("accept"); | |
return; | |
} | |
debug("accept %s.\n", sockaddr_info((struct sockaddr *)&from)); | |
FILE *r, *w; | |
#ifdef _WIN32 | |
int h = _open_osfhandle(accept_socket, _O_RDONLY|_O_BINARY); | |
r = _fdopen(h, "rb"); | |
w = _fdopen(h, "wb"); | |
// r = w = _fdopen(_open_osfhandle(accept_socket, _O_RDWR|_O_BINARY), "r+b"); | |
#else // unix | |
r = w = fdopen(accept_socket, "r+b"); | |
#endif | |
if (r == NULL || w == NULL) { | |
perror("fdopen"); | |
return; | |
} | |
if (setvbuf(w, NULL, _IONBF, 0) != 0) { | |
perror("setvbuf"); | |
} | |
request_handler(r, w); | |
//shutdown(accept_socket, SD_BOTH); | |
fclose(r); | |
fclose(w); | |
closesocket(accept_socket); | |
} // end loop | |
closesocket(listen_socket); | |
socket_cleanup(); | |
} |
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
#ifndef SERVER_H | |
#define SERVER_H | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifdef _WIN32 | |
#define PRIdSIZE "Iu" | |
#define PRIdSSIZE "Id" | |
#else | |
#define PRIdSIZE "zu" | |
#define PRIdSSIZE "zd" | |
#endif | |
// for clang x86_64-pc-windows-mscv | |
#ifdef _MSC_VER | |
#define snprintf(s,n,fmt,...) \ | |
_snprintf_s(s, n, _TRUNCATE, fmt, __VA_ARGS__) | |
#define strtok_r(s,d,p) strtok_s(s,d,p) | |
#endif | |
#define debug(...) fprintf(stderr, __VA_ARGS__) | |
void start_server(char *, void (*)(FILE *, FILE *)); | |
#endif /* SERVER_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment