2008年8月12日 星期二

TCP Server/Client 範例程式

Server的PortNumber隨便取一個大1204且不在/etc/services中出現的號碼即可
/***  TCP Server tcpserver.c
 *
 * 利用 socket 介面設計網路應用程式
 * 程式啟動後等待 client 端連線,連線後印出對方之 IP 位址
 * 並顯示對方所傳遞之訊息,並回送給 Client 端。
 *
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h>


#define SERV_PORT 5134


#define MAXNAME 1024


extern int errno;


main()
{
 int socket_fd;      /* file description into transport */
 int recfd;     /* file descriptor to accept        */
 int length;     /* length of address structure      */
 int nbytes;     /* the number of read **/
 char buf[BUFSIZ];
 struct sockaddr_in myaddr; /* address of this service */
 struct sockaddr_in client_addr; /* address of client    */
/*                             
 *      Get a socket into TCP/IP
 */
 if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
  perror ("socket failed");
  exit(1);
 }
/*
 *    Set up our address
 */
 bzero ((char *)&myaddr, sizeof(myaddr));
 myaddr.sin_family = AF_INET;
 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 myaddr.sin_port = htons(SERV_PORT);


/*
 *     Bind to the address to which the service will be offered
 */
 if (bind(socket_fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) <0) {
  perror ("bind failed");
  exit(1);
 }


/*
 * Set up the socket for listening, with a queue length of 5
 */
 if (listen(socket_fd, 20) <0) {
  perror ("listen failed");
  exit(1);
 }
/*
 * Loop continuously, waiting for connection requests
 * and performing the service
 */
 length = sizeof(client_addr);
 printf("Server is ready to receive !!\n");
 printf("Can strike Cntrl-c to stop Server >>\n");
 while (1) {
  if ((recfd = accept(socket_fd,
      (struct sockaddr_in *)&client_addr, &length)) <0) {
   perror ("could not accept call");
   exit(1);
         }


  if ((nbytes = read(recfd, &buf, BUFSIZ)) < 0) {
   perror("read of data error nbytes !");
   exit (1);
  }
   
  printf("Create socket #%d form %s : %d\n", recfd,
  inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
  printf("%s\n", &buf);
 
  /* return to client */
  if (write(recfd, &buf, nbytes) == -1) {
   perror ("write to client error");
   exit(1);
  }
  close(recfd);
  printf("Can Strike Crtl-c to stop Server >>\n");
 }
}

/*  TCP  Client program (tcpclient.c)
 *
 *  本程式啟動後向 Server (tcpserver) 要求連線,
 *  並送出某檔案給 Server,再由 Server 收回該檔案
 *  並顯示出該檔案的內容
 *
 */


#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>


#define SERV_PORT 5134
#define MAXDATA   1024


#define MAXNAME 1024
main(argc, argv)
int argc;
char **argv;
{
 int fd;      /* fd into transport provider */
 int i;      /* loops through user name */
 int length;     /* length of message */
 int fdesc;     /* file description */
 int ndata;     /* the number of file data */
 char data[MAXDATA]; /* read data form file */
 char data1[MAXDATA];  /*server response a string */
 char buf[BUFSIZ];     /* holds message from server */
 struct hostent *hp;   /* holds IP address of server */
 struct sockaddr_in myaddr;   /* address that client uses */
 struct sockaddr_in servaddr; /* the server's full addr */


 /*
  * Check for proper usage.
  */
 if (argc < 3) {
  fprintf (stderr,
   "Usage: %s host_name(IP address) file_name\n", argv[0]);
  exit(2);
 }
 /*
  *  Get a socket into TCP/IP
  */
 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  perror ("socket failed!");
  exit(1);
 }
 /*
  * Bind to an arbitrary return address.
  */
 bzero((char *)&myaddr, sizeof(myaddr));
 myaddr.sin_family = AF_INET;
 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 myaddr.sin_port = htons(0);


 if (bind(fd, (struct sockaddr *)&myaddr,
   sizeof(myaddr)) <0) {
  perror("bind failed!");
  exit(1);
 }
 /*
  * Fill in the server's address and the data.
  */


 bzero((char *)&servaddr, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_port = htons(SERV_PORT);


 hp = gethostbyname(argv[1]);
 if (hp == 0) {
  fprintf(stderr,
   "could not obtain address of %s\n", argv[2]);
  return (-1);
 }


 bcopy(hp->h_addr_list[0], (caddr_t)&servaddr.sin_addr,
  hp->h_length);
 /*
  * Connect to the server連線.
  */
 if (connect(fd, (struct sockaddr *)&servaddr,
    sizeof(servaddr)) < 0) {
  perror("connect failed!");
  exit(1);
 }
 /**開起檔案讀取文字 **/
 fdesc = open(argv[2], O_RDONLY);
 if (fdesc == -1) {
  perror("open file error!");
  exit (1);
 }
 ndata = read (fdesc, data, MAXDATA);
 if (ndata < 0) {
  perror("read file error !");
  exit (1);
 }
 data[ndata] = '\0';


 /* 發送資料給 Server */
 if (write(fd, data, ndata) == -1) {
  perror("write to server error !");
  exit(1);
 }
 /** 由伺服器接收回應 **/
 if (read(fd, data1, MAXDATA) == -1) {
  perror ("read from server error !");
  exit (1);
 }
 /* 印出 server 回應 **/
 printf("%s\n", data1);


 close (fd);
}



 

Makefileall:tcpserver tcpclient
tcpserver:tcpserver.c
gcc $^ -o $@
tcpclient:tcpclient.c
gcc $^ -o $@


底下是另一個TCP Client的範例
用C實作TCP socket連接/讀/寫,使用fcntl設定nonblocking以處理connect overtime情況,使用select來處理socket讀寫overtime。

/* 
 
 * on Unix: 
 
 *    cc -c connector.c 
 
 *    cc -o connector connector.o 
 
 * 
 
 * on Windows NT: 
 
 *    open connector.c in Visual Studio 
 
 *    press 'F7' to link -- a project to be created 
 
 *    add wsock32.lib to the link section under project setting 
 
 *    press 'F7' again 
 
 * 
 
 * running: 
 
 *    type 'connector' for usage 
 
 */ 
 
 
#include <stdio.h>  
 
#include <stdlib.h>  
 
#include <string.h>  
 
#include <stdarg.h>  
 
#include <errno.h>  
 
#include <fcntl.h>  
 
#ifdef WIN32  
 
#include <winsock2.h>  
 
#else  
 
#include <unistd.h>  
 
#include <sys/types.h>  
 
#include <sys/socket.h>  
 
#include <sys/ioctl.h>  
 
#include <netinet/in.h>  
 
#include <arpa/inet.h>  
 
#include <netdb.h>  
 
#endif  
 
 
#ifndef INADDR_NONE  
 
#define INADDR_NONE     0xffffffff  
 
#endif  
 
#define MAX_STRING_LEN  1024  
 
#define BUFSIZE  2048  
 
 
#ifndef WIN32  
 
#define SOCKET int  
 
#else  
 
#define errno WSAGetLastError()  
 
#define close(a) closesocket(a)  
 
#define write(a, b, c) send(a, b, c, 0)  
 
#define read(a, b, c) recv(a, b, c, 0)  
 
#endif  
 
 
char buf[BUFSIZE];  
 
 
static char i_host[MAX_STRING_LEN];  /* site name */ 
 
static char i_port[MAX_STRING_LEN];  /* port number */ 
 
 
void err_doit(int errnoflag, const char *fmt, va_list ap);  
 
void err_quit(const char *fmt, ...);  
 
int tcp_connect(const char *host, const unsigned short port);  
 
void print_usage();  
 
 
//xnet_select x defines  
 
#define READ_STATUS  0  
 
#define WRITE_STATUS 1  
 
#define EXCPT_STATUS 2  
 
 
/* 
 
s    - SOCKET 
 
sec  - timeout seconds 
 
usec - timeout microseconds 
 
x    - select status 
 
*/ 
 
SOCKET xnet_select(SOCKET s, int sec, int usec, short x)  
 
{  
 
 int st = errno;  
 
 struct timeval to;  
 
 fd_set fs;  
 
 to.tv_sec = sec;  
 
 to.tv_usec = usec;  
 
 FD_ZERO(&fs);  
 
 FD_SET(s, &fs);  
 
 switch(x){  
 
  case READ_STATUS:  
 
  st = select(s+1, &fs, 0, 0, &to);  
 
  break;  
 
  case WRITE_STATUS:  
 
  st = select(s+1, 0, &fs, 0, &to);  
 
  break;  
 
  case EXCPT_STATUS:  
 
  st = select(s+1, 0, 0, &fs, &to);  
 
  break;  
 
 }  
 
 return(st);  
 
}  
 
 
int tcp_connect(const char *host, const unsigned short port)  
 
{  
 
    unsigned long non_blocking = 1;  
 
    unsigned long blocking = 0;  
 
    int ret = 0;  
 
    char * transport = "tcp";  
 
    struct hostent      *phe;   /* pointer to host information entry    */ 
 
    struct protoent *ppe;       /* pointer to protocol information entry*/ 
 
    struct sockaddr_in sin;     /* an Internet endpoint address  */ 
 
    SOCKET s;                    /* socket descriptor and socket type    */ 
 
    int error;  
 
 
#ifdef WIN32  
 
    {  
 
        WORD wVersionRequested;  
 
        WSADATA wsaData;  
 
        int err;  
 
   
 
        wVersionRequested = MAKEWORD( 2, 0 );  
 
   
 
        err = WSAStartup( wVersionRequested, &wsaData );  
 
        if ( err != 0 ) {  
 
            /* Tell the user that we couldn't find a usable */ 
 
            /* WinSock DLL.                               */ 
 
            printf("can't initialize socket library\n");  
 
            exit(0);  
 
        }  
 
    }  
 
#endif      
 
      
 
    memset(&sin, 0, sizeof(sin));  
 
    sin.sin_family = AF_INET;  
 
      
 
    if ((sin.sin_port = htons(port)) == 0)  
 
        err_quit("invalid port \"%d\"\n", port);  
 
      
 
    /* Map host name to IP address, allowing for dotted decimal */ 
 
    if ( phe = gethostbyname(host) )  
 
        memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);  
 
    else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )  
 
        err_quit("can't get \"%s\" host entry\n", host);  
 
      
 
    /* Map transport protocol name to protocol number */ 
 
    if ( (ppe = getprotobyname(transport)) == 0)  
 
        err_quit("can't get \"%s\" protocol entry\n", transport);  
 
      
 
    /* Allocate a socket */ 
 
    s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);  
 
    if (s < 0)  
 
        err_quit("can't create socket: %s\n", strerror(errno));  
 
      
 
    /* Connect the socket with timeout */ 
 
#ifdef WIN32  
 
    ioctlsocket(s,FIONBIO,&non_blocking);  
 
#else  
 
    ioctl(s,FIONBIO,&non_blocking);  
 
#endif  
 
    //fcntl(s,F_SETFL, O_NONBLOCK);  
 
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){  
 
        struct timeval tv;   
 
        fd_set writefds;  
 
        // 设置连接超时时间  
 
        tv.tv_sec = 10; // 秒数  
 
        tv.tv_usec = 0; // 毫秒  
 
        FD_ZERO(&writefds);   
 
        FD_SET(s, &writefds);   
 
        if(select(s+1,NULL,&writefds,NULL,&tv) != 0){   
 
            if(FD_ISSET(s,&writefds)){  
 
                int len=sizeof(error);   
 
                //下面的一句一定要,主要针对防火墙   
 
                if(getsockopt(s, SOL_SOCKET, SO_ERROR,  (char *)&error, &len) < 0)  
 
                    goto error_ret;   
 
                if(error != 0)   
 
                    goto error_ret;   
 
            }  
 
            else 
 
                goto error_ret; //timeout or error happen   
 
        }  
 
        else goto error_ret; ;   
 
 
#ifdef WIN32  
 
        ioctlsocket(s,FIONBIO,&blocking);  
 
#else  
 
        ioctl(s,FIONBIO,&blocking);  
 
#endif  
 
 
    }  
 
    else{  
 
error_ret:  
 
        close(s);  
 
        err_quit("can't connect to %s:%d\n", host, port);  
 
    }  
 
    return s;  
 
}  
 
 
void err_doit(int errnoflag, const char *fmt, va_list ap)  
 
{  
 
    int errno_save;  
 
    char buf[MAX_STRING_LEN];  
 
 
    errno_save = errno;   
 
    vsprintf(buf, fmt, ap);  
 
    if (errnoflag)  
 
        sprintf(buf + strlen(buf), ": %s", strerror(errno_save));  
 
    strcat(buf, "\n");  
 
    fflush(stdout);  
 
    fputs(buf, stderr);  
 
    fflush(NULL);  
 
    return;  
 
}  
 
 
/* Print a message and terminate. */ 
 
void err_quit(const char *fmt, ...)  
 
{  
 
    va_list ap;  
 
    va_start(ap, fmt);  
 
    err_doit(0, fmt, ap);  
 
    va_end(ap);  
 
    exit(1);  
 
}  
 
 
#ifdef WIN32  
 
char *optarg;  
 
 
char getopt(int c, char *v[], char *opts)  
 
{  
 
    static int now = 1;  
 
    char *p;  
 
 
    if (now >= c) return EOF;  
 
 
    if (v[now][0] == '-' && (p = strchr(opts, v[now][1]))) {  
 
        optarg = v[now+1];  
 
        now +=2;  
 
        return *p;  
 
    }  
 
 
    return EOF;  
 
}  
 
 
#else  
 
extern char *optarg;  
 
#endif  
 
 
#define required(a) if (!a) { return -1; }  
 
 
int init(int argc, char *argv[])  
 
{  
 
    char c;  
 
    //int i,optlen;  
 
    //int slashcnt;  
 
 
    i_host[0]  =  '\0';  
 
    i_port[0]  =  '\0';  
 
 
    while ((c = getopt(argc, argv, "h:p:?")) != EOF) {  
 
        if (c == '?')  
 
            return -1;  
 
        switch (c) {   
 
        case 'h':  
 
            required(optarg);  
 
            strcpy(i_host, optarg);  
 
            break;  
 
        case 'p':  
 
            required(optarg);  
 
            strcpy(i_port, optarg);  
 
            break;  
 
        default:  
 
            return -1;  
 
        }  
 
    }  
 
 
    /*  
 
     * there is no default value for hostname, port number,  
 
     * password or uri 
 
     */ 
 
    if (i_host[0] == '\0' || i_port[0] == '\0')  
 
        return -1;  
 
 
    return 1;  
 
}  
 
 
void print_usage()  
 
{  
 
    char *usage[] =  
 
    {  
 
        "Usage:",  
 
        "    -h    host name",  
 
        "    -p    port",  
 
        "example:",  
 
        "    -h 127.0.0.1 -p 4001",  
 
    };     
 
    int i;  
 
 
    for (i = 0; i < sizeof(usage) / sizeof(char*); i++)  
 
        printf("%s\n", usage[i]);  
 
      
 
    return;  
 
}  
 
 
int main(int argc, char *argv[])  
 
{  
 
    SOCKET fd;  
 
    int n;  
 
 
    /* parse command line etc ... */ 
 
    if (init(argc, argv) < 0) {  
 
        print_usage();  
 
        exit(1);  
 
    }  
 
 
    buf[0] = '\0';  
 
 
    /* pack the info into the buffer */       
 
    strcpy(buf, "HelloWorld");  
 
 
    /* make connection to the server */ 
 
    fd = tcp_connect(i_host, (unsigned short)atoi(i_port));  
 
 
    if(xnet_select(fd, 0, 500, WRITE_STATUS)>0){  
 
        /* send off the message */ 
 
        write(fd, buf, strlen(buf));  
 
    }  
 
    else{  
 
        err_quit("Socket I/O Write Timeout %s:%s\n", i_host, i_port);  
 
    }  
 
 
    if(xnet_select(fd, 3, 0, READ_STATUS)>0){  
 
        /* display the server response */ 
 
        printf("Server response:\n");  
 
        n = read(fd, buf, BUFSIZE);  
 
        buf[n] = '\0';  
 
        printf("%s\n", buf);  
 
    }  
 
    else{  
 
        err_quit("Socket I/O Read Timeout %s:%s\n", i_host, i_port);  
 
    }  
 
    close(fd);  
 
 
#ifdef WIN32  
 
    WSACleanup();  
 
#endif  
 
 
    return 0;  
 
}

資料來源:
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/tcpserver.c
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/tcpclient.c
http://www.zeali.net/entry/13

沒有留言: