- 追加された行はこの色です。
- 削除された行はこの色です。
[[MinGWによるWindows Programming]]
MinGW で Windows Socket を使うには -lwsock32 をつける。
Windows Socket 2 を使う場合は -lws2_32 である。
Console 型の server program の例を以下に示す。
この例題のソースを
srv.c として保存し srv.exe を作るには、コマンドラインは
gcc -DWIN32 srv.c -lwsock32 -o srv.exe
のようにする。Windows Socket 2 の場合は、
ソース中のインクルードファイル名 winsock.h を winsock2.h
に置き換えた後
gcc -DWIN32 srv.c -lws2_32 -o srv.exe
のようにする。
なお、この例題は multi-thread の例題にもなっている。
* 例題プログラム機能説明 [#mff0d93d]
- TCP port 6543 (SERV_TCP_PORT)を listen する。
- 接続があれば thread を生成し関数server() を起動する。
- server() では Client から受け取る文字は改行毎に文字列として処理する。
-- 文字列 "date" を受け取ると、server 側の daytime を文字列
で送信する。
-- 文字列 "exit" を受け取ると、そのTCP接続を閉じ、thread を終了する。
-- それ以外の文字列を受け取ると文字列 "OK" に network 改行を
付加して送信する。
* 例題プログラムの手抜き等 [#r4f13a6b]
ソースコードを見ればすぐにわかるが、thread 関数の引数を手抜きして
いる。本来 pointer を渡すべきところを cast でごまかして SOCKET
そのものを渡している。つまり SOCKET の size が void pointer より
小さいことを仮定している。
* 例題プログラムソース [#i5b7460e]
/* srv.c */
#define STRICT
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef WIN32
#include <windows.h>
#include <winsock.h>
#include <process.h>
#else
#ifdef SOLARIS
#include <thread.h>
#else
#include <pthread.h>
#endif
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#endif
/*---------------------------------------------------
* Program:
* simple tcp server
*
* Purpose:
* Socket and multi-thread application program
* that acts as a server for the tcp service on
* the local machine. It listens on port SERV_TCP_PORT
* and answers according to the command from clients.
*
* Use:
* testsrv
*
* Author:
* Based on the program by Barry Shein, Boston University
* Modified for Win32-console and winsock by Hirofumi Fujii, KEK
*
* Date:
* Original Version - January, 1987
* Modified for Win32-console and winsock - January, 1997
*
* Reference:
* Comer, Douglas E.,
* Internetworking with TCP/IP Vol. I, 2nd. Ed.,
* Section 21.27, pp. 359-362, Prentice-Hall (1991),
* ISBN 0-13-468505-9.
*
* Comile and Link:
* MinGW
* gcc -DWIN32 srv.c -lwsock32 -o srv.exe
*
* Microsoft Visual C++ 4.0
* cl /MT /W3 /DWIN32 srv.c wsock32.lib
*
* Digital UNIX V3.2D-1 (Rev. 41)
* cc srv.c -o srv -threads
*
* SunOS 5.4
* cc -DSOLARIS srv.c -o srv -lthread -lsocket
*/
#define BACKLOG 5 /* number of requests we're willing to queue */
#define MAXCMDLINE 256 /* maximum command line length */
#define SERV_TCP_PORT 6543
#ifndef WIN32
void
closesocket( SOCKET s )
{
close( s );
}
#endif
int
netstart( void )
{
#ifdef WIN32
WSADATA wsadata;
WORD wsaversion;
wsaversion = 0x0101;
return( WSAStartup( wsaversion, &wsadata ) );
#else
return 0; /* Always no error */
#endif
}
void
netclose( SOCKET sockfd )
{
#ifdef WIN32
if( sockfd != INVALID_SOCKET )
closesocket( sockfd );
WSACleanup();
#else
if( sockfd >= 0 )
close( sockfd );
#endif
return;
}
void
server( void *s )
{
SOCKET sock;
char rbuf[BUFSIZ+1];
char sbuf[BUFSIZ+1];
char cmnd[MAXCMDLINE+1];
int i;
int ncmnd;
int nrecv;
int nsend;
time_t tnow;
/* Copy the socket */
sock = (SOCKET)s;
ncmnd = 0;
while(1)
{
/*
* Get one line request
*/
if((nrecv = recv( sock, rbuf, BUFSIZ, 0 )) <= 0 )
{
closesocket( sock );
#ifdef WIN32
_endthread();
#else
return;
#endif
}
/*
* Fill command line
*/
for( i = 0; i < nrecv; i++ )
{
if((rbuf[i] == 0x0d) || (rbuf[i] == 0x0a))
{
/* ASCII-CR or ASCII-LF */
cmnd[ncmnd] = '\0'; /* Null terminate */
/*
* Return reply
*/
if( strcmp( "exit", cmnd ) == 0 )
{
closesocket( sock );
#ifdef WIN32
_endthread();
#else
return;
#endif
}
else if( strcmp( "date", cmnd ) == 0 )
{
time( &tnow );
strcpy( sbuf, ctime( &tnow ) );
nsend = strlen( sbuf );
if( sbuf[nsend - 1] == 0x0a )
nsend--;
if( sbuf[nsend - 1] == 0x0d )
nsend--;
sbuf[nsend++] = 0x0d;
sbuf[nsend++] = 0x0a;
sbuf[nsend] = '\0';
send( sock, sbuf, nsend, 0 );
}
else if( ncmnd > 0 )
{
sprintf( sbuf, "OK\015\012" );
send( sock, sbuf, strlen( sbuf ), 0 );
}
ncmnd = 0;
}
else if( (rbuf[i] >= ' ') && ((rbuf[i] & 128) == 0) )
{
if( ncmnd < MAXCMDLINE )
cmnd[ncmnd++] = rbuf[i];
}
}
}
}
int
main( int argc, char *argv[] )
{
SOCKET s, t; /* socket descriptors */
int i; /* general purpose integer */
struct sockaddr_in sa, isa; /* Internet socket addr. structure */
char *myname; /* pointer to name of this program */
#ifndef WIN32
#ifdef SOLARIS
thread_t thread;
#else
pthread_t thread;
#endif
#endif
myname = argv[0];
/*
* Load the TCP/IP module (winsock)
*/
if( netstart() != 0 )
{
fprintf( stderr, "%s: cannot load the network module.\n", myname );
exit(1);
}
/*
* Put the socket number and our address info
* into the socket structure
*/
memset((char *)&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons( SERV_TCP_PORT );
sa.sin_addr.s_addr = htonl( INADDR_ANY );
/*
* Allocate an open socket for incoming connections
*/
#ifdef WIN32
if( (s = socket( AF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET )
if( (s = socket( PF_INET, SOCK_STREAM, 0 )) == INVALID_SOCKET )
#else
if( (s = socket( AF_INET, SOCK_STREAM, 0 )) < 0 )
if( (s = socket( PF_INET, SOCK_STREAM, 0 )) < 0 )
#endif
{
netclose( s );
fprintf( stderr, "%s: Cannot allocate socket\n", myname );
exit(2);
}
/*
* Bind the socket to the service port
* so we hear incoming connections
*/
#ifdef WIN32
if( bind( s, (const struct sockaddr *)&sa, sizeof( sa ) ) == SOCKET_ERROR )
#else
if( bind( s, (const struct sockaddr *)&sa, sizeof( sa ) ) < 0 )
#endif
{
netclose( s );
fprintf( stderr, "%s: Cannot bind the socket.\n", myname );
exit(2);
}
/*
* Set maximum connections we will fall behing
*/
listen( s, BACKLOG );
/*
* Go into an infinite loop waiting for new connections
*/
while(1)
{
i = sizeof( isa );
/*
* We hang in accept() while waiting for new customers
*/
#ifdef WIN32
if((t = accept( s, (struct sockaddr *)&isa, &i )) == INVALID_SOCKET )
#else
if((t = accept( s, (struct sockaddr *)&isa, &i )) < 0 )
#endif
{
netclose( s );
fprintf( stderr, "%s: Cannot accept the connetion.\n", myname );
exit(2);
}
/* create and start the new thread */
#ifdef WIN32
_beginthread( server, 0,(void *)t );
#else
#ifdef SOLARIS
thr_create( NULL, 0, server, (void *)t, (long)0, &thread );
#else
pthread_create( &thread, pthread_attr_default,
(pthread_startroutine_t)server, (pthread_addr_t)t );
#endif
#endif
}
}
Clinet 側は telnet で行えばよい。