开发平台:Linux 开发工具:Ubuntu, sourceInsight4.0 项目介绍: 本项目基于TCP/IP协议创建一个网络通信系统,可以实现客户之间的聊天通信以及文件传输,同时利用进程实现多客户群聊,多个客户也可同时从服务器下载文件实现文件共享,客户可向服务器发送ls命令获取服务器端的文件目录,并发送get+filename获取文件,也可发送put+filename上传文件到服务器。 protocol.h
#ifndef __PROTOCOL_H__ #define __PROTOCOL_H__ #define FTP_ROOT_DIR "/home/gec/tftp" //命令号, 命令参数 //命令号-> 整数 enum CMD_NO { FTP_CMD_LS = 1024, // FTP_CMD_GET, FTP_CMD_PUT, FTP_CMD_BYE, FTP_CMD_NUM // 命令个数 }; //出错码 enum resp_result { RESP_SUCCESS = 0, //成功 RESP_PACK_ERROR, //失败,包的长度不对 RESP_PACK_NOEND, //包没有结束,可以再次收包 RESP_PACK_NOFILE //没有可以获取的文件 }; //参数: 参数长度, 参数内容 /* 0xc0 : 包头 pkg_len ;//4bytes, 小端模式,整个数据包的长度 4(pkg_len) + 4 (cmd_no) + arg_1 +... cmd_no // 4bytes, 小端模式 arg_1; arg_1_len; //4bytes , 小端模式 arg_1_data; len长度 arg_2: arg_2_len; //4bytes,小端模式 arg_2_data; .... 0xC0:包尾 */ // cmd: ls //0xc0 ___包长度______ __命令号()__ 0xc0 // 0xc0 0x80 0x00 0x00 0x00 //cmd: get //0xc0 ____包长度(4)___ ___命令号(4)___ ___arg_1_Len(4)_ ___filename(r)___ 0xc0 #if 0 unsigned char cmd[1024]; int i = 0; int pkg_len = 1024; cmd[0] = 0xc0; cmd[1] = pkg_len & 0xff; cmd[2] = ( pkg_len >> 8) & 0xff; cmd[3] = (pkg_len >> 16) & 0xff; cmd[4] = (pkg_len >> 24) & 0xff; #endif //CMD_RESP /* 0xc0: 包头 pkg_len: 整个数据包的长度,4bytes, 小端模式 cmd_no : 命令号,4bytes, 小端模式,表示回复哪条命令 resp_len: 回复内容的长度,4bytes, 小端模式 result + resp_conent 1 + x result: 执行成功或失败,1 bytes , 0表示成功,其他表示失败 resp_conent: 回复内容 成功: ls: 文件名字 各文件名之间用空格分隔 get: 文件大小,4bytes, 小端模式 失败: 出错码 0xc0:包尾 */ //ls 的回复 // 0xc0 --pkg_Len(4)--- ---cmd_No(4)--- --resp_len(4)-- --result(1)-- --filenames(r, 名字以空格分开)--- 0xc0 //get 的回复 //0xc0 ---pkg_len(4)--- ----cmd_no(4)--- ---resp_len(4)--- ---result(1)-- --file_size(4, 小端模式)-- 0xc0 #endiftcp_client.c
#include <sys/types.h> /* See NOTES */ #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <linux/socket.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include "protocol.h" int connect_server(char *ip,int port) { /**1.创建套接字**/ int sockfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == sockfd) { perror("socket error"); return -1; } /**2.发起链接请求**/ int ret; struct sockaddr_in sAddr; memset(&sAddr,0,sizeof(sAddr)); sAddr.sin_family = AF_INET; sAddr.sin_port = htons(port); sAddr.sin_addr.s_addr = inet_addr(ip); ret = connect(sockfd,(struct sockaddr*)&sAddr,sizeof(sAddr)); if(-1 ==ret) { perror("conncet error"); return -1; } // return sockfd; } void send_cmd(int sockfd,unsigned char *cmd,int len) { // int ret = send(sockfd,cmd,len,0); if(-1 == ret) { perror("send cmd error"); return; } // } void recv_ls_val(int sockfd) { /** 服务器回复数据,事先会回复一个数据包 0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小 紧接着服务器会回复正文 size个字节的数据 **/ int i=0; unsigned char ch = 0; unsigned char cmd[500] = {0}; /*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要 do { // read(sockfd,&ch,1); perror("read ls"); }while(ch != 0xc0); // //排除连续的0xc0 while(ch == 0xc0) { read(sockfd,&ch,1); }//确保读取的是数据包的第一个字节 // while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束 { cmd[i++] = ch; read(sockfd,&ch,1); } /***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长 int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24; if(cmd_len != i) { printf("read value error,the pack len is no right\n"); //send_error(connfd); return; } //解析验证信息 int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24; if(err_no == RESP_PACK_ERROR) { printf("cmd error\n"); return; } int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24; printf("recv data len:%d\n",data_len); /*****************************************解析完毕**********************************************************/ /****************************************接收回复正文*******************************************************/ memset(cmd,0,300); printf("data_len %d\n",data_len); recv(sockfd,cmd,data_len,0); printf("recv data is:%s\n",cmd); } void send_ls(int sockfd) { /* ls 命令的数据包: 0xc0 L E N S C M D S 0xc0 4个字节表示包的长度 4个字节表示命令 */ int i = 0; int pak_len = 4+4; unsigned char cmd[50] ={0}; /**********************************组合数据包***************************************************/ /**帧头**/ cmd[i++] = 0xc0; /**包长**/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /**命令**/ cmd[i++] = FTP_CMD_LS & 0xff; cmd[i++] = FTP_CMD_LS>>8 & 0xff; cmd[i++] = FTP_CMD_LS>>16 & 0xff; cmd[i++] = FTP_CMD_LS>>24 & 0xff; /**帧尾**/ cmd[i++] = 0xc0; /******************************数据包组合完毕***************************************************/ /**发送命令**/ send_cmd(sockfd,cmd,i); //将数据包发送出去后,等待服务器的处理结果 /**接收返回结果**/ recv_ls_val(sockfd); } void recv_get_val(int sockfd,int fd) { /** 服务器回复数据,事先会回复一个数据包 0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小 紧接着服务器会回复正文 size个字节的数据 **/ int i=0; unsigned char ch = 0; unsigned char cmd[300] = {0}; /*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要 do { // read(sockfd,&ch,1); }while(ch != 0xc0); //排除连续的0xc0 while(ch == 0xc0) { read(sockfd,&ch,1); }//确保读取的是数据包的第一个字节 while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束 { cmd[i++] = ch; read(sockfd,&ch,1); } /***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长 int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24; if(cmd_len != i) { printf("read value error,the pack len is no right\n"); //send_error(connfd); return; } //解析验证信息 int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24; if(err_no == RESP_PACK_ERROR) { printf("cmd error\n"); return; } int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24; printf("recv data len:%d\n",data_len); /*****************************************解析完毕**********************************************************/ /*****************************************接收文件数据******************************************************/ unsigned char *p = (unsigned char *)malloc(data_len+1); int ret=0; while(1) { ret += read(sockfd,p+ret,data_len); if(ret == data_len) { break; } else if(ret == -1 || ret == 0) { perror("read error"); return; } } write(fd,p,data_len);//将正文写入本地文件 /********************************************判断文件是否发送完成*******************************************************/ if(err_no == RESP_PACK_NOEND) //文件内容没有发完,会在后续发送 { recv_get_val(sockfd,fd); //再次接收后续包 } } void send_get(int sockfd,char *file) { /** get命令包格式: 0xc0 L E N S C M D S S I Z E A R G S . . . . 0xc0 包长(4bytes) 命令号(6bytes) 参数长度(4bytes) 参数正文(size bytes) **/ int arg_len = strlen(file); int pak_len = 4 + 4 + 4 + arg_len; unsigned char cmd[50] = {0}; //保存命令数据包 int i=0; /****************************************封装命令包****************************************************/ /*包头*/ cmd[i++] = 0Xc0; /*包长 小端模式*/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /*命令号 小端模式*/ cmd[i++] = FTP_CMD_GET & 0xff; cmd[i++] = FTP_CMD_GET>>8 & 0xff; cmd[i++] = FTP_CMD_GET>>16 & 0xff; cmd[i++] = FTP_CMD_GET>>24 & 0xff; /*参数长度*/ cmd[i++] = arg_len & 0xff; cmd[i++] = arg_len>>8 & 0xff; cmd[i++] = arg_len>>16 & 0xff; cmd[i++] = arg_len>>24 & 0xff; /*参数正文*/ int j=0; for(j=0;j<arg_len;j++) { cmd[i++] = file[j]; } /*包尾*/ cmd[i++] = 0xc0; /********************************************封包完成****************************************************/ /*发送命令*/ send_cmd(sockfd,cmd,i); /*接收回复*/ int fd = open(file,O_RDWR|O_CREAT|O_TRUNC,0777); if(-1 == fd) { perror("open error"); return; } recv_get_val(sockfd,fd); close(fd); } void send_file_data1(int sockfd,int fd,int file_len) { /* L E N S E R R N S I Z E */ unsigned char cmd[50] = {0}; unsigned char buf[256] = {0}; int pak_len; int size; int i; int ret = 0; while(1) { size = read(fd,buf,256); if(size == 0 || size==-1) { perror("read error"); break; } pak_len = 4 + 4 + 4; ret += size; /*帧头*/ i = 0; cmd[i++] = 0xc0; /*包长 小端模式*/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /*回复码*/ if(ret < file_len) //文件没完 { cmd[i++] = RESP_PACK_NOEND & 0xff; cmd[i++] = RESP_PACK_NOEND>>8 & 0xff; cmd[i++] = RESP_PACK_NOEND>>16 & 0xff; cmd[i++] = RESP_PACK_NOEND>>24 & 0xff; } else { cmd[i++] = RESP_SUCCESS & 0xff; cmd[i++] = RESP_SUCCESS>>8 & 0xff; cmd[i++] = RESP_SUCCESS>>16 & 0xff; cmd[i++] = RESP_SUCCESS>>24 & 0xff; } /*正文长度*/ cmd[i++] = size & 0xff; cmd[i++] = size>>8 & 0xff; cmd[i++] = size>>16 & 0xff; cmd[i++] = size>>24 & 0xff; /*帧尾*/ cmd[i++] = 0xc0; send_cmd(sockfd,cmd,i); //回复数据包 send(sockfd,buf,size,0); //回复正文 } } void send_put(int sockfd,char *file) { /** get命令包格式: 0xc0 L E N S C M D S S I Z E A R G S . . . . 0xc0 包长(4bytes) 命令号(6bytes) 参数长度(4bytes) 参数正文(size bytes) **/ int arg_len = strlen(file); int pak_len = 4 + 4 + 4 + arg_len; unsigned char cmd[50] = {0}; //保存命令数据包 int i=0; /****************************************封装命令包****************************************************/ /*包头*/ cmd[i++] = 0Xc0; /*包长 小端模式*/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /*命令号 小端模式*/ cmd[i++] = FTP_CMD_PUT & 0xff; cmd[i++] = FTP_CMD_PUT>>8 & 0xff; cmd[i++] = FTP_CMD_PUT>>16 & 0xff; cmd[i++] = FTP_CMD_PUT>>24 & 0xff; /*参数长度*/ cmd[i++] = arg_len & 0xff; cmd[i++] = arg_len>>8 & 0xff; cmd[i++] = arg_len>>16 & 0xff; cmd[i++] = arg_len>>24 & 0xff; /*参数正文*/ int j=0; for(j=0;j<arg_len;j++) { cmd[i++] = file[j]; } /*包尾*/ cmd[i++] = 0xc0; /********************************************封包完成*****************************************/ /*发送命令*/ send_cmd(sockfd,cmd,i); /*发送文件内容*/ int fd = open(file,O_RDONLY); if(-1==fd) { perror("open error"); return; } int file_len = lseek(fd,0,SEEK_END); //获取文件大小 lseek(fd,0,SEEK_SET); send_file_data1(sockfd,fd,file_len); //发送文件内容 close(fd); } int main(int argc,char *argv[]) { int sockfd = connect_server(argv[1],atoi(argv[2])); if(-1 == sockfd) { return -1; } unsigned char cmd[5] = {0}; unsigned char file[20] = {0}; while(1) { memset(cmd,0,5); scanf("%s",cmd); // ls <--- 查看服务器文件列表 // get file <--- 从服务器获取文件列表 // put file <--- 上传文件到服务器 // bye <--- 告知服务器断开链接 if( strcmp(cmd,"ls") == 0 ) { // send_ls(sockfd); } else if(strcmp(cmd,"get")==0) // get 1.txt { scanf("%s",file); send_get(sockfd,file); } else if(strcmp(cmd,"put")==0) { scanf("%s",file); send_put(sockfd,file); } } /**5.处理并退出**/ close(sockfd); return 0; }tcp_server.c
#include <sys/types.h> #include <sys/stat.h> /* See NOTES */ #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <linux/socket.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <dirent.h> #include "protocol.h" #define FTP_DIR "/home/gec/tftp" void send_pack(int connfd,unsigned char *cmd,int len) { // printf("%d %x\n",connfd,cmd[0]); int ret = send(connfd,cmd,len,0); if(-1 == ret) { perror("send cmd error"); return; } // } void send_error(int connfd) { int i = 0; int pak_len = 4+4; unsigned char cmd[50] ={0}; /**帧头**/ cmd[i++] = 0xc0; /**包长**/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /**错误码**/ cmd[i++] = RESP_PACK_ERROR & 0xff; cmd[i++] = RESP_PACK_ERROR>>8 & 0xff; cmd[i++] = RESP_PACK_ERROR>>16 & 0xff; cmd[i++] = RESP_PACK_ERROR>>24 & 0xff; /**帧尾**/ cmd[i++] = 0xc0; /**发送回复数据**/ send_pack(connfd,cmd,i); } void repa_ls(int connfd) { int i = 0; int pak_len = 0; unsigned char file[500] = {0}; unsigned char cmd[500] = {0}; DIR *dirp = opendir(FTP_DIR); if(NULL == dirp) { perror("open dir error"); return ; } // struct dirent *dir; while((dir = readdir(dirp)) != NULL) { sprintf(file+strlen(file),"%s ",dir->d_name); printf("%d %s\n",strlen(file),dir->d_name); } // /**帧头**/ cmd[i++] = 0xc0; /**包长**/ pak_len = 4 + 4 + 4; cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /**错误码**/ cmd[i++] = RESP_SUCCESS & 0xff; cmd[i++] = RESP_SUCCESS>>8 & 0xff; cmd[i++] = RESP_SUCCESS>>16 & 0xff; cmd[i++] = RESP_SUCCESS>>24 & 0xff; /**回复数据长度**/ cmd[i++] = strlen(file) & 0xff; cmd[i++] = strlen(file)>>8 & 0xff; cmd[i++] = strlen(file)>>16 & 0xff; cmd[i++] = strlen(file)>>24 & 0xff; printf("recv ls data size %d\n",strlen(file)); printf("%s\n",file); /**帧尾**/ cmd[i++] = 0xc0; send_pack(connfd,cmd,i); //回复命令的处理结果 send_pack(connfd,file,strlen(file));//回复命令数据 // } void send_file_data(int connfd,int fd,int file_len) { /* L E N S E R R N S I Z E */ unsigned char cmd[50] = {0}; unsigned char buf[256] = {0}; int pak_len; int size; int i; int ret = 0; while(1) { size = read(fd,buf,256); if(size == 0 || size==-1) { perror("read error"); break; } pak_len = 4 + 4 + 4; ret += size; /*帧头*/ i = 0; cmd[i++] = 0xc0; /*包长 小端模式*/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /*回复码*/ if(ret < file_len) //文件没完 { cmd[i++] = RESP_PACK_NOEND & 0xff; cmd[i++] = RESP_PACK_NOEND>>8 & 0xff; cmd[i++] = RESP_PACK_NOEND>>16 & 0xff; cmd[i++] = RESP_PACK_NOEND>>24 & 0xff; } else { cmd[i++] = RESP_SUCCESS & 0xff; cmd[i++] = RESP_SUCCESS>>8 & 0xff; cmd[i++] = RESP_SUCCESS>>16 & 0xff; cmd[i++] = RESP_SUCCESS>>24 & 0xff; } /*正文长度*/ cmd[i++] = size & 0xff; cmd[i++] = size>>8 & 0xff; cmd[i++] = size>>16 & 0xff; cmd[i++] = size>>24 & 0xff; /*帧尾*/ cmd[i++] = 0xc0; send_pack(connfd,cmd,i); //回复数据包 send(connfd,buf,size,0); //回复正文 } } void repa_get(int connfd,unsigned char *cmd) { /************************************解析get参数*******************************************************/ int i = 8; int arg_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24; char *file = (char *)malloc(arg_len+1); memset(file,0,arg_len+1); for(i=0;i<arg_len;i++) { file[i] = cmd[12+i]; //获取文件名 } /************************************打开文件读取数据并准备回复************************************************/ int pak_len = 0; i=0; char ftp_file[100] = {0}; sprintf(ftp_file,"%s/%s",FTP_DIR,file); int fd = open(ftp_file,O_RDONLY); if(-1 == fd) { perror("open error"); /*帧头*/ cmd[i++] = 0xc0; pak_len = 8; /*包长 小端模式*/ cmd[i++] = pak_len & 0xff; cmd[i++] = pak_len>>8 & 0xff; cmd[i++] = pak_len>>16 & 0xff; cmd[i++] = pak_len>>24 & 0xff; /*回复码*/ cmd[i++] = RESP_PACK_NOFILE & 0xff; cmd[i++] = RESP_PACK_NOFILE>>8 & 0xff; cmd[i++] = RESP_PACK_NOFILE>>16 & 0xff; cmd[i++] = RESP_PACK_NOFILE>>24 & 0xff; /*帧尾*/ cmd[i++] = 0xc0; send_pack(connfd,cmd,i); } else { int file_len = lseek(fd,0,SEEK_END); //获取文件大小 lseek(fd,0,SEEK_SET); send_file_data(connfd,fd,file_len); //回复文件内容 close(fd); } } void recv_get_val1(int connfd,int fd) { /** 服务器回复数据,事先会回复一个数据包 0xc0 L E N S E R R N S I Z E 0xc0 回复数据包长度 回复的验证信息 后续正文大小 紧接着服务器会回复正文 size个字节的数据 **/ int i=0; unsigned char ch = 0; unsigned char cmd[300] = {0}; /*************************************接收回复数据包*******************************************************/ //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要 do { // read(connfd,&ch,1); }while(ch != 0xc0); //排除连续的0xc0 while(ch == 0xc0) { read(connfd,&ch,1); }//确保读取的是数据包的第一个字节 while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束 { cmd[i++] = ch; read(connfd,&ch,1); } /***************************************数据包接收完成*****************************************************/ /******************************************解析数据包******************************************************/ //解析包长 int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24; if(cmd_len != i) { printf("read value error,the pack len is no right\n"); //send_error(connfd); return; } //解析验证信息 int err_no = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24; if(err_no == RESP_PACK_ERROR) { printf("cmd error\n"); return; } int data_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24; printf("recv data len:%d\n",data_len); /*****************************************解析完毕**********************************************************/ /*****************************************接收文件数据******************************************************/ unsigned char *p = (unsigned char *)malloc(data_len+1); int ret=0; while(1) { ret += read(connfd,p+ret,data_len); if(ret == data_len) { break; } else if(ret == -1 || ret == 0) { perror("read error"); return; } } write(fd,p,data_len);//将正文写入本地文件 /********************************************判断文件是否发送完成*******************************************************/ if(err_no == RESP_PACK_NOEND) //文件内容没有发完,会在后续发送 { recv_get_val1(connfd,fd); //再次接收后续包 } } void repa_put(int connfd,unsigned char *cmd) { int i = 8; int arg_len = cmd[8] | cmd[9]<<8 | cmd[10]<<16 | cmd[11]<<24; char *file = (char *)malloc(arg_len+1); memset(file,0,arg_len+1); for(i=0;i<arg_len;i++) { file[i] = cmd[12+i]; //获取文件名 } char ftp_file[100] = {0}; sprintf(ftp_file,"%s/%s",FTP_DIR,file); int fd = open(ftp_file,O_RDWR|O_CREAT|O_TRUNC,0777); if(-1 == fd) { perror("open error"); return; } recv_get_val1(connfd, fd); } int recv_cmd(int connfd) { int i=0; unsigned char ch = 0; unsigned char cmd[50] = {0}; while(1) { //命令以0xc0开头,所以如果收到的不是0xc0则舍弃不要 do { read(connfd,&ch,1); }while(ch != 0xc0); //排除连续的0xc0 while(ch == 0xc0) { read(connfd,&ch,1); }//确保读取的是数据包的第一个字节 i=0; while(ch != 0xc0)//读到的是数据包的内容,读到包尾结束 { cmd[i++] = ch; read(connfd,&ch,1); } int cmd_len = cmd[0] | cmd[1]<<8 | cmd[2]<<16 | cmd[3]<<24; if(cmd_len != i) { printf("read cmd error,the pack len is no right\n"); send_error(connfd); return 0; } int cmd_num = cmd[4] | cmd[5]<<8 | cmd[6]<<16 | cmd[7]<<24; switch(cmd_num)//判断收到的命令 { case FTP_CMD_LS: repa_ls(connfd); break; case FTP_CMD_GET: repa_get(connfd,cmd); break; case FTP_CMD_PUT: repa_put(connfd,cmd); break; } } } int main(int argc,char *argv[]) { /**1.创建套接字**/ int sockfd = socket(AF_INET,//IPv4协议族 SOCK_STREAM,//流式套接字 0//默认协议 ); if(-1 == sockfd) { perror("socket error"); return -1; } /**设置套接字选项**/ int val = 1; setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&val,4);//允许地址重用 setsockopt(sockfd,SOL_SOCKET,SO_REUSEPORT,&val,4);//允许端口重用 /**2.绑定地址**/ struct sockaddr_in sAddr;//以太网协议地址结构体 <--- 方便赋值 memset(&sAddr,0,sizeof(sAddr)); sAddr.sin_family = AF_INET;//协议族 sAddr.sin_port = htons(atoi(argv[2]));//网络字节序的短整型 sAddr.sin_addr.s_addr =inet_addr(argv[1]);//网络字节序的u32整数 int ret; ret = bind(sockfd,//绑定的套接字 (struct sockaddr*)&sAddr,//该套接字绑定的"地址" sizeof(sAddr)//地址长度 );//将套接字与"地址"绑定 if(-1 == ret) { perror("bind error"); return -1; } /**3.设置监听**/ ret = listen(sockfd,10); if(-1 == ret) { perror("listen error"); return -1; } /**4.等待链接**/ int connfd; struct sockaddr_in cAddr; socklen_t addrlen = sizeof(cAddr); while(1) { connfd = accept(sockfd,//套接字描述符,表示等待那个套接字上的链接 (struct sockaddr*)&cAddr,//"地址"空间,用来保存客户端的地址 &addrlen//空间,用来保存客户端地址长度 );//如果有客户端链接,服务器端接受请求并返回链接描述符 //链接描述符是用来与 对应的客户端进行通信 if(-1 == connfd) { perror("accept error"); return -1; } printf("connect client is:%s:%d\n",inet_ntoa(cAddr.sin_addr),ntohs(cAddr.sin_port)); pid_t pid = fork(); if(pid > 0) { close(connfd); continue; } else if(pid == 0) { // recv_cmd(connfd); exit(0); } } /**7.处理并退出**/ close(sockfd); close(connfd); return 0; }