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 の例題にもなっている。

例題プログラム機能説明

例題プログラムの手抜き等

ソースコードを見ればすぐにわかるが、thread 関数の引数を手抜きして いる。本来 pointer を渡すべきところを cast でごまかして SOCKET そのものを渡している。つまり SOCKET の size が void pointer より 小さいことを仮定している。

例題プログラムソース

/* 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 )
#else
  if( (s = socket( AF_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 で行えばよい。


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS