计算机网络2——客户端软件的实现(C++)

设计一个connectsock过程封装底层代码(UDP和TCP共用)。

/* consock.cpp - connectsock */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <winsock.h>

#ifndef INADDR_NONE
#define INADDR_NONE  0xffffffff
#endif /* INADDR_NONE */

void errexit(const char*,...);
/*-------------------------------------------------------
* connectsock - allocate & connect a socket using TCP or UDP
*------------------------------------------------------
*/
// 参数:服务器端点地址、服务器的服务号、传输层协议
SOCKET connectsock(const char *host,const char *service,const char *transport){
    struct hostent *phe; /* pointer to host information entry */
    struct servent *pse; /* pointer to service information entry */
    struct protoent *ppe; /* pointer to protocol information entry */
    struct sockaddr_in sin; /* an Internet endpoint address */
    int s,type; /* socket descriptor and socket type */
    memset(&sin,0,sizeof(sin));
    sin.sin_family=AF_INET; // 给端点地址的地址族赋值

    /* Map service name to port number */
    if(pse=getservbyname(service,transport))
        sin.sin_port=pse->s_port;
    else if((sin.sin_port=htons((u_short)atoi(service)))==0)
        errexit("can't get \"%s\" service entry\n",service);

    /* 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)
        errexit("can't get \"%s\" host entry\n",host);

    /* Map protocol name to protocol number */
    if((ppe=getprotobyname(transport))==0)
        errexit("can't get \"%s\" protocol entry\n",transport);

    /* Use protocol to choose a socket type */
    if(strcmp(transport,"udp")==0)
        type=SOCK_DGRAM;
    else
        type=SOCK_STREAM;
    /* Allocate a socket */
    s=socket(PF_INET,type,ppe->p_proto); // 创建套接字
    if(s==INVALID_SOCKET)
        errexit("can't create socket: %d\n",GetLastError());
    /* Connect the socket */ // 连接服务器
    if(connect(s,(struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
        errexit("can't connect to %s.%s: %d\n",host,service,
    GetLastError());
    return s;
}

设计connectUDP过程,用于创建连接模式客户端UDP套接字。

/* conUDP.cpp - connectUDP */
#include <winsock.h>
SOCKET connectsock(const char *,const char *,const char *);
/*-------------------------------------------------------
* connectUDP - connect to a specified UDP service
* on a specified host
*-----------------------------------------------------
*/
SOCKET connectUDP(const char *host,const char *service){
    return connectsock(host,service,"udp");
}

设计connectTCP过程,用于创建客户端TCP套接字。

/* conTCP.cpp - connectTCP */
#include <winsock.h>
SOCKET connectsock(const char *,const char *,const char *);
/*----------------------------------------------------
* connectTCP - connect to a specified TCP service
* on a specified host
*---------------------------------------------------
*/
SOCKET connectTCP(const char *host,const char *service){
    return connectsock(host,service,"tcp");
}

异常处理。

/* errexit.cpp - errexit */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
/*----------------------------------------------------------
* errexit - print an error message and exit
*----------------------------------------------------------
*/
/* VARARGS1 */
void errexit(const char *format,...){
    va_list args;
    va_start(args,format);
    vfprintf(stderr,format,args);
    va_end(args);
    WSACleanup(); // 清除资源的占用
    exit(1);
}

【例】访问DAYTIME服务的客户端

DAYTIME服务,获取日期和时间。双协议服务(TCP、UDP),端口号13。TCP版利用TCP连接请求触发服务,UDP版需要客户端发送一个请求。

/* TCPdtc.cpp - main,TCPdaytime */
#include <stdlib.h>
#include <stdio.h>
#include <winsock.h>
void TCPdaytime(const char *,const char *);
void errexit(const char *,...);
SOCKET connectTCP(const char *,const char *);

#define LINELEN  128
#define WSVERS MAKEWORD(2,0)
/* 对于UDP,#define MSG “what daytime is it?\n” */
/*--------------------------------------------------------
* main - TCP client for DAYTIME service
*--------------------------------------------------------
*/
int main(int argc,char *argv[]){
    // 客户端与服务器端运行在同一主机
    char *host="localhost"; /* host to use if none supplied */
    char *service="daytime"; /* default service port */
    WSADATA wsadata;
    switch(argc){
        case 1:
            host="localhost";
            break;
        case 3:
            service=argv[2];
            /* FALL THROUGH */
        case 2:
            host=argv[1];
            break;
        default:
            fprintf(stderr,"usage: TCPdaytime[host [port]]\n");
            exit(1);
    }
    if(WSAStartup(WSVERS,&wsadata)!=0)
        errexit("WSAStartup failed\n");
    TCPdaytime(host,service);
    WSACleanup();
    return 0; /* exit */
}

/*-----------------------------------------------------
* TCPdaytime-invoke Daytime on specified host and print results
*-----------------------------------------------------
*/
void TCPdaytime(const char *host,const char *service){
    char buf[LINELEN+1]; /* buffer for one line of text */
    SOCKET s; /* socket descriptor */
    int cc; /* recv character count */
    s=connectTCP(host,service);

    cc=recv(s,buf,LINELEN,0);
    while(cc!=SOCKET_ERROR && cc>0){
        buf[cc]='\0'; /* ensure null-termination */
        (void) fputs(buf,stdout);
        cc=recv(s,buf,LINELEN,0);
    }
    closesocket(s);
}

对于UDP版,前面的代码与TCP几乎相同。

void UDPdaytime(const char *host,const char *service){
    char buf[LINELEN+1]; /* buffer for one line of text */
    SOCKET s; /* socket descriptor */
    int n; /* recv character count */

    s=connectUDP(host,service);
    (void)send(s,MSG,strlen(MSG),0);
    
    /* Read the daytime */
    n=recv(s,buf,LINELEN,0);
    if(n==SOCKET_ERROR)
        errexit("recv failed: recv() error %d\n",GetLastError());
    else{
        buf[cc]='\0'; /* ensure null-termination */
        (void)fputs(buf,stdout);
    }
    closesocket(s);
    return 0; /* exit */
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值