网络Socket--客户端的源代码解析

附上笔记之前的传送门:http://blog.csdn.net/PipiAvenger/article/details/79414863

客户端:

    1.客户端程序通过命令行参数指定服务器端的参数;

    2.客户端程序在连接服务器时,发送自己的用户名和密码给服务器端;

    2.如果用户名和密码出错则程序退出否则从标准输入中读入字符串,然后将该字符串发送给服务器端;

    4.从服务器端接收到的数据打印到标准输出上;

代码如下:

C语言:
/* Some unix Program Standard head file */
#include<stido.h>
#include<stdlib.h>
#include<unitsd.h>
#include<stirng.h>
#include<getopt.h>    /* getopt_long(int argc ,char * const argv[],const char *optstring,const struct option *longopts, int *longindex) */
#inlcude<libgen.h>    /* basename() */

/* Socket Program head file */
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>    /* sockaddr_in{} and other Internet define */

#include<errno.h>    /* strerror(),perror(), errno head file */
#inlcude<arpa/inet.h>    /* For inet_pton() */
#define MAX_BUF_SIZE                         1024
#define LOGON_INFO                     "guozhihao:******"

#define MAJOR                     1
#define MINOR                     0
#define REVER                       0    /* 版本号 */

void print_version(char *progname)    /*progname为文件名*/ /*打印函数*/
{
    printf("%s version 1.0.0\n",progname);
    printf("Copyright (C) 2012 GuoZhihao<810170156@qq.com>.\n");
    return ;
}

void print_usage(char *progname)    /*打印打开文件时提示信息函数*/
{
    print_version(progname);

    printf("usage: %s [OPTION]...\n",progname);
    printf(" %s is a socket client test program , which used to logon server and send string to sever \n",progname);

    printf("\nMandatory arguments to long options are mandatory for short options too: \n");

    printf(" -i[ipaddr    ]    Socket server IP address\n");
    printf(" -p[port    ]    Socket server Port address\n");
    printf(" -h[help    ]    Display this help information\n");
    printf(" -v[version    ]    Display the program version\n");

    printf("\nExample: %s -i 192.168.92.128 -p 8888\n",progname);
    return ;
}

/*Argc is the program linux running command argument count, and argv is the arguments string value. All of the arguments take as string.*/
int main(int argc,char argv[][])    /*主函数开始处*/
{
    int                             sockfd,len,rv;    /*sockfd是网络通信的文件描述符*/    /*len和rv用来判断服务器传出信息的变量*/
    int                             opt;                  /*switch调用的opt表达式*/
    char                          *progname = NULL;    /*对progname赋值为NULL防止它为随机值*/
    char                          *server_ip = NULL;    /*对ip地址进行初始化*/
    unsigned short          ser_port = 0;    /*对端口进行初始化*/
    char                          buf[MAX_BUF_SIZE];    /*定义缓冲区*/
    struct sockaddr_in     servaddr;    /*定义网络通信通用兼容IPV4/IPV6结构体*/

    struct option             long_options[] =    /* 函数getopt()的结构体以第一个参数是长选项--ipaddr,第二个是必须跟上选项,第四个短选项-i */
    {
        {"ipaddr",required_argument,NULL, 'i'},
        {"port",required_argument,NULL, 'p'},
        {"version",no_argument,NULL, 'v'},
        {"help",no_argument,NULL, 'h'},
        {NULL,0,NULL,0}
    };

    progname = basename(argv[0]);    //取文件目录名

    /* Parser the command line parameters 解析命令行参数,如参数p、v、h、i*/
    while((opt = getopt_long(argc,argv,"i:p:vh",long_options,NULL))!= -1)  
/******为啥不同于opt = getopt_long(argc,argv,"i:p:vh",long_options,NULL)
opt !=-1这两句结合在一起? *******/  
    {    
        switch(opt)
        {
            case 'p':     /*-p获取端口int atoi(const char *nptr)是将字符串转换成整型数的一个函数函数,getopt_long中optarg是指向当前选项参数的指针*/
                    server_port = atoi(optarg);   
                    break;

            case 'i':    /*-i获取IP地址*/
                    server_ip = optarg;    
                    break;

            case 'v':    /*-v打印版本信息*/
                    print_version(progname);    /* Defined in version.h*/
                    return EXIT_SUCCESS;

            case 'h':    /* -h打印使用说明Get help information*/
                    print_suage(progname);
                    return EXIT_SUCCESS;
               
            default:
                    break;
        }
    }

    if(NULL==server_ip || 0==server_port)    /*r如果使用者没有输入ip地址或者端口则打印使用说明*/
    {
        print_usage(progname);
        return -1;
    }

    /*Open an IPV4(AF_INET) TCP(SOCK_STREAM) Socket File Descripition, UDP socket should use SOCK_DGRAM,We can use linux command "man socket" to see this function manual创建一个socket使用IPV4,遵循TCP协议,类型:TCP报文*/
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)/*判断sockfd文件描述符是否被创建*/
    {
        /*Strerror() is the 1st way to display the failure reason, argument errno is a globle variable defined in <errno.h>, we can use linux command "man strerror" to see this function manual可通过strerror(errno)来解释出错的原因*/
        printf("Use socket() to create a TCP socket failure: %s\n",strerror(errno));
        return -1;
    }
    /* Now we set the Server Information, include IPV4 or IPV6,Server port,Server IP address设置客户端信息*/
    memset(&servaddr,0,sizeof(servaddr));    /*将通用的设置重置为0*/
    servaddr.sin_family = AF_INET;    /* Set it as IPV4 protocal*/
    servaddr.sin_port = htons(server_port);    /*Server port 函数hotons()在LP4解释*/
    
    /* argv[1] we take as Server IP address , it's the second arguments in running command */
    if(inet_pton(AF_INET, server_ip,&servaddr.sin_addr) <= 0)/*判断IP、端口是否赋值成功*/
    {
        printf("Use inte_pton() to set the Server IP address failure.\n");
        rv = -2;
        goto Cleanup;    /*传入到Cleanup处理*/
    }
    
    /* Now call connect() function to connect to the server, we can use linux command "man connect" to see this function manual连接服务器*/
    if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0)    /*判断是否连接成功*/
    {
        printf("Connect to server [%s:%d] failure: %s\n", server_ip,server_port,strerror(errno));
        rv = -3;
        goto Cleanup;    /*传入到Cleanup处理*/
    }
    printf("Connect to Server [%s:%d] ok\n",server_ip, server_port);    /*打印连接成功*/

    if(write(sockfd, LOGON_INFO, strlen(LOGON_INFO))< 0)    /*判断写入个人信息是否传递成功*/
    {
        printf("write logon informantion to server failure: %s\n",strerror(errno));
        goto Cleanup;    /*传入到Cleanup处理*/
    }
    /*Once we connect to the server successfully, we can receive the data from the socket socket 连接成功即可通信*/
    memset(buf,0,sizeof(buf));    /*清空缓冲区,目的是为了存放读取的数据len*/
    if((len = read(sockfd, buf, MAX_BUF_SIZE)) < 0)    /*判断服务器传出信息是否接收到*/
    {
        printf("socket read data from server [%s] failure:%s\n", server_ip,strerror(errno));
        goto Cleanup;    /*传入到Cleanup处理*/
    }
    else if(0 == len)    /*判断通信连接是否中断*/
    {
        printf("logon to server [%s] failure and socket disconnected\n",server_ip);
        goto Cleanup;    /*传入到Cleanup处理*/
    }

    /* socket read data from server */
    if(strncasecmp(buf, "passed", 6))    /*收到服务器信息为passed时,登入失败*/
    {
        printf("Logon to server[%s] failure: %s\n", server_ip, buf);
        goto Cleanup;    /*传入到Cleanup处理*/
    } 
    printf("Logon to server successfully!\n");    /*打印登入成功*/
}
    while(1)    /*开始通信*/
    {
        printf("\nplease input string to send to server:\n==> ");

        memset(buf, 0, sizeof(buf));    /*存放服务器的传入的信息*/ 
        fgets(buf, sizeof(buf), stdin);    /*从标准输入获取信息*/
        write(sockfd,buf,strlen(buf));    /*写到buf中去*/

        memset(buf,0,sizeof(buf));    /*清空buf里的值*/
        rv=read(sockfd, buf, sizeof(buf));    /*返回buf中总的字节数*/
        if(rv <= 0)    /*判断rv的返回值*/
        {
            printf("ERROR:socket disconnected or get error\n");
            goto Cleanup;    /*传入到Cleanup处理*/
        }
        printf("<==%s\n",buf);
    }


Cleanup:    /*Cleanup处理*/
    close(sockfd);    /* We must close socket File Description when program exit关闭文件描述符*/
    return 0;



 

注:红色为待修改

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值