附上笔记之前的传送门: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;
注:红色为待修改