本程序的文件传输系统的实现包含服务端模块、客户端模块,使用流式套接字。在设计时设计客户端和服务端两个界面时,客户端的所有信息发往服务器端,再由服务器端进行消息的分析处理并做出相应的操作,服务器端时所有信息的中心。本程序可实现互相聊天、互相传送、以及查询删除文件。
系统界面 2. 服务器端功能
连接控制:启动服务器,断开服务器、侦听、连接客户端、打印客户端连接信息;
信息处理:接收客户端与服务器交互的信息,并做出相应的处理;
聊天功能:接收客户端聊天请求,进行一对一聊天;
文件传输:接收客户端文件传输请求,可进行发送、接收、查询、删除文件;
3. 客户端功能
连接功能:输入服务器地址,实现连接服务器及断开功能;信息处理:接收由服务器端发送来的信息,并做出相应的相应;聊天功能:向服务器端发送聊天请求,等待服务器端回应,进行一对一聊天;文件传输:向服务器发送文件传输请求,可进行上传、下载、续传、删除文件、查询文件列表文件;4. 代码段 server.cpp
主界面
#include "stdio.h" #include "winsock2.h" #include "stdlib.h" #include "windows.h" #include "direct.h" #include "io.h" #include <time.h> #pragma comment(lib,"ws2_32.lib") #define SERVERIP "127.0.0.1" #define SERVERPORT 3333 SOCKET sockServer; SOCKADDR_IN addrServer; //实例化一个addr来存放地址信息 SOCKADDR_IN peerAddr; SOCKET sockConn; #define SIZE 8192 #define BUFSIZE 8192 typedef struct LS { char name[1024]; //文件名 int size; //文件字节数 }LS; LS listfile[1000]; int num=0; int filenum=0; char filename[1024]; int recvFile(); int sendFile(char *filename); int sendFileList(); int delFileList();//删除文件 int testNum(); int print_clientIP(SOCKET s,sockaddr_in name,int *namelen); void listFile(char *path, int layer); void SockStartup(); void recvRequest(); void closeSocket(); void sendWords(); char recvBuf[BUFSIZE]; char sendBuf[BUFSIZE]; int len = sizeof(sockaddr); int main(void) { system("color e0"); //添加背景色 printf("\t\t\t☆*****************************☆\n"); printf("\t\t\t☆ 欢迎使用本系统!(服务器端) ☆\n"); printf("\t\t\t☆*****************************☆\n"); while(1) { SockStartup(); recvRequest(); closeSocket(); WSACleanup(); } system("pause"); return 0; }启动socket,与客户端建立连接
void SockStartup() { WSADATA data; //初始化win socket网络库,申请2.2的版本 int ret=WSAStartup(MAKEWORD(2,2),&data); if (SOCKET_ERROR==ret) { return; } //创建一个无指定协议的流式套接字 sockServer=socket(AF_INET,SOCK_STREAM,0); if (INVALID_SOCKET==sockServer) { WSACleanup(); return; } if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2){ printf("请求协议版本失败!\n"); return; } memset(&addrServer,0,sizeof(struct sockaddr_in)); addrServer.sin_family=AF_INET; //指定IP地址地址版本人为IPV4 addrServer.sin_addr.S_un.S_addr=inet_addr(SERVERIP); //存放服务器ip地址 addrServer.sin_port=htons(SERVERPORT); //存放端口信息 ret=bind(sockServer,(struct sockaddr*)&addrServer,sizeof(struct sockaddr)); if (SOCKET_ERROR==ret) { closesocket(sockServer); WSACleanup(); return; } //监听连接请求的状态以及接收客户发出的连接请求,1为正在等待连接的最大队列长度 printf("监听客户的连接……\n"); ret=listen(sockServer,5); if (SOCKET_ERROR==ret) { closesocket(sockServer); WSACleanup(); return; } int len=sizeof(struct sockaddr); //accept()接收客户端由connect()发出的连接请求 ,原来的sock sockConn=accept(sockServer,NULL,&len); if (INVALID_SOCKET==sockConn) { printf("错误"); closesocket(sockServer); WSACleanup(); return; } int peerLen=20; print_clientIP(sockConn,peerAddr,&peerLen); printf("接收到客户端的连接\n"); printf("..........连接成功!..........\n"); }关闭socket
void closeSocket() { closesocket(sockConn); }打印客户端的IP
int print_clientIP(SOCKET s,sockaddr_in name,int *namelen){//打印客户端ip getpeername(s, (struct sockaddr *)&name, namelen); //获取connfd表示的连接上的对端地址 printf("接收到客户端%s的连接\n",inet_ntoa(name.sin_addr)); return 0; }请求回应函数
void recvRequest() { //char choiceRev[10]; while(1) { Sleep(2000); system("cls"); //清屏 printf("监听客户端的请求......\n"); if(SOCKET_ERROR==recv(sockConn,recvBuf,sizeof(recvBuf),0) ){ printf("与客户端断开连接!\n"); Sleep(2000); system("cls"); return; } else if(!strcmp("1",recvBuf)) { printf("客户端请求与你聊天!你是否同意请求?(Y/N)\n"); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf),0); //sendto(sockServer,) if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0){ sendWords(); Sleep(2000); }else{ printf("重新监听客户端的请求……\n"); } }else if(!strcmp("2",recvBuf)) { printf("客户端请求你发送文件!你是否同意请求?(Y/N)\n"); fflush(stdin); gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf),0); if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0){ printf("请输入要发送文件的文件名:\n "); fflush(stdin); gets(filename); sendFile(filename); Sleep(2000); }else{ printf("重新监听客户端的请求……\n"); } }else if(!strcmp("3",recvBuf)) { printf("客户端请求向你发送文件!你是否同意请求?(Y/N)\n"); fflush(stdin); //清空缓存区 gets(sendBuf); int a; send(sockConn,sendBuf,sizeof(sendBuf,0), 0); if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0) { do { fflush(stdin); a = recvFile(); Sleep(2000); if (a ==-1) //如果文件名输错 { continue; } recv(sockConn,recvBuf,sizeof(recvBuf),0); } while ((strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0)); }else{ printf("重新监听客户端的请求……\n"); } }else if(!strcmp("4",recvBuf)) { //path文件名可修改自己电脑里的目录 char path[255] = "F:\\dirent-master"; printf("客户端请求查询目录!你是否同意请求?(Y/N)\n"); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf,0), 0); if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0) { num = 0; memset(listfile, 0, sizeof(listfile)); listFile(path,0); sendFileList(); Sleep(2000); } else{ printf("重新监听客户端的请求……\n"); } }else if(!strcmp("5",recvBuf)) {//删除文件 printf("请输入要查询的目录\n"); char path[255]; fflush(stdin); //清空缓存区 gets(path); printf("客户端请求查询目录!你是否同意请求?(Y/N)\n"); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf,0), 0); if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0) { num = 0; memset(listfile, 0, sizeof(listfile)); listFile(path,0); delFileList(); Sleep(2000); } else{ printf("重新监听客户端的请求……\n"); } }else if(!strcmp("6",recvBuf)) {//猜数字游戏 printf("客户端请求玩猜数字游戏!你是否同意请求?(Y/N)\n"); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf),0); if(strcmp("Y",sendBuf)==0 || strcmp("y",sendBuf)==0){ testNum(); Sleep(2000); }else{ printf("重新监听客户端的请求……\n"); } }else if(strcmp("0",recvBuf)==0){ printf("与客户端断开连接!\n");printf("recvBuf:%s", recvBuf); Sleep(2000); system("cls"); //清屏 return; } else { printf("recvBuf:%s", recvBuf); } } }小游戏
int testNum(){//猜数字游戏 srand((int)time(0)); int num=rand()%10; int findnum; fflush(stdin); //清空缓存区 sendBuf[0]=num; printf("答案是:%d\n",num); //send(sockConn,sendBuf,sizeof(sendBuf),0); //while(1){ recv(sockConn,recvBuf,sizeof(recvBuf),0); findnum=recvBuf[0]-'0'; if(num==findnum){ printf("客户端猜的是%d,对了! 答案是:%d\n",findnum,num); sendBuf[1]=1; send(sockConn,sendBuf,sizeof(sendBuf),0); //break; }else if(findnum<num||findnum>num){ //printf("猜小了\n"); sendBuf[1]=0; printf("客户端猜的是%d,错了! 结果是:%d\n",findnum,num); send(sockConn,sendBuf,sizeof(sendBuf),0); } //} return 0; }与客户端聊天功能
void sendWords() { system("cls"); printf("开始聊天!输入exit退出聊天程序\n"); while(1) { if(SOCKET_ERROR==recv(sockConn,recvBuf,sizeof(recvBuf),0) ){ printf("错误!\n"); return; } if(strcmp("exit",recvBuf)==0) { printf("对方已退出聊天程序!\n"); return; } printf("client:\n %s\n\n",recvBuf); printf("server:\n "); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockConn,sendBuf,sizeof(sendBuf),0); if(strcmp("exit",sendBuf)==0) { system("cls"); printf("退出聊天程序!\n重新等待客服端的请求\n"); break; } printf("\n"); } }服务器发送文件
int sendFile(char *filename) { int ret,cnt,len1,lenlast; FILE *fp; int totlen; int file_block_length; int count=0; //发送的次数 int send_sum = 0; //当前已发送文件长度 int current = 0; //进度条长度 int progress = 50; //统计接受大小 fp=fopen(filename,"rb"); if (NULL==fp) { printf("~~~~~~~ 文件打开失败 ! ~~~~~~~\n"); strcpy(sendBuf,"ERROR"); send(sockConn,sendBuf,strlen(sendBuf)+1,0); return -1; } //设置流 stream 的文件位置为给定的偏移 offset ,相当于定位到文件尾 fseek(fp,0,SEEK_END); //函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。相当得到文件大小 */ totlen=ftell(fp); printf("文件%s的长度为%d字节\n",filename,totlen); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,filename); //向客户端发送文件名 ret=send(sockConn,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { return -1; } memset(recvBuf,0,sizeof(recvBuf)); //收到客户端发回来的文件名确定信息 ret=recv(sockConn,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) ) { printf("未收到文件名确认信息"); return -1; } printf("向客户端发送文件名成功\n"); memset(sendBuf,0,sizeof(sendBuf)); //将文件大小长度 转换成字符串存入sendBuf 指向的内存空间 itoa(totlen,sendBuf,10); //给客户端发送文件长度 ret=send(sockConn,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { return -1; } memset(recvBuf,0,sizeof(recvBuf)); ret=recv(sockConn,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) ) { return -1; } printf("向客户端发送文件长度成功\n"); cnt=totlen/SIZE; len1=SIZE; if (totlen%SIZE) { lenlast=totlen-cnt*SIZE; cnt=cnt+1; } printf("\n\n文件长度为%d字节,\n每次传送%d字节,\n需要分%d次传送\n", totlen,SIZE,cnt); //重新指向文件头 rewind(fp); //读取文件指定大小元素,且元素个数 Sleep(1000); while(!feof(fp)) { //file_block_length = fread(sendBuf,SIZE,1,fp); file_block_length = fread(sendBuf, sizeof(char), SIZE, fp); send_sum += file_block_length; current = send_sum / (totlen / progress); printf("\r"); printf("["); for (int i = 0; i < progress; i++) { putchar(i < current ? '=' : '+'); } printf("]"); printf(" %8ld/%ld %6.2f%%", send_sum, totlen, (float)send_sum / totlen * 100); if(file_block_length < SIZE) { int rest_length = totlen-count*SIZE; //printf("\n剩余字符%d\n", rest_length); if(send(sockConn,sendBuf,rest_length,0) < 0) { printf("####L(%d) send file:%s failed\n", __LINE__, filename); break; } } else if(send(sockConn,sendBuf,SIZE,0) < 0) { printf("####L(%d) send file:%s failed\n", __LINE__, filename); break; } memset(sendBuf,0,sizeof(sendBuf)); count++; } printf("\n这个程序传送了%d次\n\n", count); printf("..........发送成功..........\n"); fclose(fp); return 0; }服务器接收文件
int recvFile() { int ret; FILE *fp; long file_size = 0; //文件大小 int recv_sum = 0; //当前接收文件长度 int current = 0; //进度条长度 int progress = 50; //统计接受大小 char filename[512]; //文件名 memset(recvBuf,0,sizeof(recvBuf)); //recv()接收数据,0表示正常接收数据 ,第三个是缓冲区长度 ret=recv(sockConn,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret) { return -1; } else if(strcmp(recvBuf,"ERROR") == 0) { printf("请重新选择文件\n"); return -1; } printf("成功接收客户端发来的文件名: %s\n",recvBuf); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,recvBuf); //send()发送数据 0表示正常发送数据 ,第三个是即将发送的缓冲区字符数 ret=send(sockConn,sendBuf,strlen(sendBuf),0); if (SOCKET_ERROR==ret) { return -1; } printf("请输入你希望保存的文件名(带扩展名)\n"); scanf("%s",filename); while(_access(".//filename",0) != -1){ puts("文件已存在!是否覆盖Y/y N/n\n"); int c = getchar(); if(getchar() == 'Y' || 'y') break; else { printf("请重新输入你希望保存的文件名(带扩展名)\n"); scanf("%s",filename); } } fp=fopen(filename,"wb"); if (NULL==fp) { return -1; } memset(recvBuf,0,sizeof(recvBuf)); //再接收文件的长度信息 ret=recv(sockConn,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret) { return -1; } printf("成功接收客户端发来的文件长度: %s\n",recvBuf); file_size = strtol(recvBuf, NULL, 10); //文件长度赋给一个长整型 printf("文件长度 :%ld\n", file_size); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,recvBuf); ret=send(sockConn,sendBuf,strlen(sendBuf),0); if (SOCKET_ERROR==ret){ return -1; } memset(recvBuf,0,sizeof(recvBuf)); while((ret = recv(sockConn,recvBuf,SIZE,0))) { if(ret<0) { printf("####L(%d) current length < 0 !\n", __LINE__); fclose(fp); exit(1); } int write_ret = fwrite(recvBuf, sizeof(char), ret, fp); //写文件 if(write_ret < ret) { printf("####L(%d) file:%s write failed write_length %d <length %d!\n", __LINE__, filename, write_ret, ret); fclose(fp); exit(1); } memset(recvBuf,0,sizeof(recvBuf)); recv_sum += ret; current = recv_sum / (file_size / progress); printf("\r"); putchar('['); for (int i = 0; i < progress; i++) { putchar(i < current ? '>' : ' '); // 输出> 或者 ' ' } putchar(']'); printf(" %8ld/%ld %6.2f%%", recv_sum, file_size, (float)recv_sum / file_size * 100); if(recv_sum == file_size) { //接收完成 printf("\n####L(%d) recv file finished ...####\n", __LINE__); break; } else if(recv_sum > file_size) { printf("\n####L(%d) recv file err recv_sum[%ld] ...####\n", __LINE__, recv_sum); break; } Sleep(10); } fclose(fp); return 0; }服务器删除文件
int delFileList() {//删除文件 char filename[1024]; //printf("文件有%d个:\n",num); //printf("\n——列出来的:——\n"); printf("\n"); int needSend; char *buffer; int ret; fflush(stdin); //清空缓存区 //传文件名称列表 for(int j=0; j<num; j++) { needSend = sizeof(listfile[j]); buffer=(char*)malloc(needSend); memcpy(buffer,&listfile[j],needSend); //printf("buffer=%s\n",buffer); ret=send(sockConn,buffer,sizeof(LS),0); //用needSend和sizeof(buffer)有问题 //ret=send(sock,buffer,needSend,0); if (SOCKET_ERROR==ret) { printf("error"); return -1; } memset(buffer,0,sizeof(buffer)); Sleep(100); } Sleep(1000); strcpy(buffer,"OK"); ret=send(sockConn,buffer,sizeof(buffer),0); printf("\n加载完毕!\n"); Sleep(500); //接收文件名 ret=recv(sockConn,filename,sizeof(filename),0); if (SOCKET_ERROR==ret) { printf("未接收到文件\n"); return -1; } else if (ret == -1 || strcmp(filename,"NOT") == 0) { recvRequest(); } else { printf("\n成功接收到文件名\n"); printf("filename:%s", filename); if(!remove(filename)){ printf("\n删除文件成功\n"); strcpy(buffer, "OK"); send(sockConn,buffer,sizeof(buffer),0); } } return 0; }查询文件列表
void listFile(char *path, int layer) { struct _finddata_t filefind; //_finddata_t结构用来记录查找到的文件的信息。 char curr[1024] = {}; //当前路径 sprintf(curr, "%s\\*.*",path); int done=0,i,handle; if(0 == strlen(curr)) { printf("文件名不能为空\n"); return; } else { // 查找目录中的第一个文件 if((handle=_findfirst(curr,&filefind))==-1) { printf("未能找到第一个文件\n"); return; } //若查找成功,返回0,失败返回-1 while(!(done=_findnext(handle,&filefind))) { if(!strcmp(filefind.name,"..")) continue; //若为二级目录,则跳过 for(i=0; i<layer; i++) printf(" "); //是否为子目录子目录 if((_A_SUBDIR == filefind.attrib)) { printf("%s(dir):\n",filefind.name); sprintf(curr, "%s\\%s",path,filefind.name); //在目录后面加上"\\"和搜索到的目录名进行下一次搜索 listFile(curr, layer+1); } else { printf("%s\t\t\t%d\n",filefind.name,filefind.size); strncpy(listfile[num].name,curr,strlen(curr)-3); strcat(listfile[num].name,filefind.name); //printf("%s\n", listfile[num].name); listfile[num].size = filefind.size; num++; //文件个数 } } } _findclose(handle); // 关闭搜索句柄 }向客户端发送查询到的文件列表
int sendFileList() { char filename[1024]; //printf("文件有%d个:\n",num); //printf("\n——列出来的:——\n"); /* for(int j=0; j<num; j++) { printf("%s\t\t\t\t\t\t%d\n", listfile[j].name, listfile[j].size); } */ printf("\n"); int needSend; char *buffer; int ret; /* char sendNum[10] = {0}; itoa(num,sendNum,10); printf("sendNum;%s\n", sendNum); //给客户端发送文件个数 ret=send(sockConn,sendNum,strlen(sendNum),0); if (SOCKET_ERROR==ret) return -1; */ fflush(stdin); //清空缓存区 //传文件名称列表 for(int j=0; j<num; j++) { needSend = sizeof(listfile[j]); buffer=(char*)malloc(needSend); memcpy(buffer,&listfile[j],needSend); //printf("buffer=%s\n",buffer); ret=send(sockConn,buffer,sizeof(LS),0); //用needSend和sizeof(buffer)有问题 //ret=send(sock,buffer,needSend,0); if (SOCKET_ERROR==ret) { printf("error"); return -1; } memset(buffer,0,sizeof(buffer)); Sleep(100); } Sleep(1000); strcpy(buffer,"OK"); ret=send(sockConn,buffer,sizeof(buffer),0); printf("\n加载完毕!\n"); Sleep(500); //接收文件名 ret=recv(sockConn,filename,sizeof(filename),0); if (SOCKET_ERROR==ret) { printf("未接收到文件\n"); return -1; } else if (ret == -1 || strcmp(filename,"NOT") == 0) { recvRequest(); } else { printf("\n成功接收到文件名\n"); printf("filename:%s", filename); sendFile(filename); } return 0; }client.cpp
#include "stdio.h" #include "stdlib.h" #include "winsock2.h" #include "windows.h" #pragma comment(lib,"ws2_32.lib") #define SERVERIP "192.168.1.32" #define SERVERPORT 3333 #define SIZE 8192 //4096//2// #define BUFSIZE 8192 int sendFile(); int recvFile(); int checkList(); int delfile();//删除文件 int testNum();//猜数字 void inquire(); void SockStartup(); void closeSocket(); void sendRequest(); void recvWords(); int rightIP(char ip_address[15]); SOCKET sockClient; SOCKADDR_IN addrServer; typedef struct LS { char name[1024]; //文件名 int size; //文件字节数 }LS; LS listfile[1000]; char recvBuf[BUFSIZE]; char sendBuf[BUFSIZE]; int main(void) { system("color e0"); printf("\t\t\t☆***************************☆\n"); printf("\t\t\t☆ 欢迎使用本系统!(客户端) ☆\n"); printf("\t\t\t☆***************************☆\n"); WSACleanup(); SockStartup(); while(1) { sendRequest(); if(sockClient == NULL) { WSACleanup(); SockStartup(); } } closeSocket(); WSACleanup(); system("pause"); return 0; } //建立socket连接 void SockStartup() { WSADATA data; int ret=WSAStartup(MAKEWORD(2,2),&data); if (SOCKET_ERROR==ret){ return; } sockClient=socket(AF_INET,SOCK_STREAM,0); if (INVALID_SOCKET==sockClient) { perror("create socket fail\n"); WSACleanup(); return; } if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2){ printf("请求协议版本失败!\n"); return; } //memset(&addrServer,0,sizeof(struct sockaddr_in)); char str[15]; printf("请输入主机的IP地址——格式如(127.0.0.1)\n"); gets(str); if (rightIP(str) == -1) { printf("连接不成功!请重新建立连接!\n"); closesocket(sockClient); WSACleanup(); SockStartup(); return; } addrServer.sin_family=AF_INET; addrServer.sin_addr.S_un.S_addr=inet_addr(str); addrServer.sin_port=htons(SERVERPORT); printf("等待服务器......\n"); //connect()提出与一个人服务器建立连接的请求 ret=connect(sockClient,(sockaddr*)&addrServer,sizeof(struct sockaddr)); if (SOCKET_ERROR==ret) { printf("连接不成功!请重新建立连接!\n"); closesocket(sockClient); WSACleanup(); SockStartup(); return; } printf("连接服务器成功\n"); } //关闭socket void closeSocket(){ closesocket(sockClient); } //请求服务列表 void sendRequest() { Sleep(1000); //睡眠等待2秒 system("cls"); printf("★***********************★\n"); printf("☆ 1.聊天 ☆\n"); printf("☆ 2.下载文件 ☆\n"); printf("☆ 3.传送文件 ☆\n"); printf("☆ 4.查看/修改文件 ☆\n"); printf("☆ 5.删除服务端文件 ☆\n"); printf("☆ 6.猜数字游戏 ☆\n"); printf("☆ 0.退出 ☆\n"); printf("★***********************★\n"); printf("请选择:\n"); fflush(stdin); //清空缓存区 gets(sendBuf); send(sockClient,sendBuf,sizeof(sendBuf),0); while(1) { if(strcmp("1", sendBuf) == 0) { Sleep(2000); system("cls"); //清屏 printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { recvWords(); return; }else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } } else if (strcmp("2", sendBuf) == 0) { Sleep(2000); system("cls"); printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { recvFile(); return; } else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } }else if (strcmp("3", sendBuf) == 0) { Sleep(2000); system("cls"); printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { int a = sendFile(); while (a == 0) { fflush(stdin); printf("是否还要传输文件(Y/N)?\n"); gets(sendBuf); send(sockClient,sendBuf,sizeof(sendBuf),0); if (strcmp("Y",sendBuf)==0||strcmp("y",sendBuf)==0) { a = sendFile(); } else if(strcmp("N",sendBuf)==0||strcmp("n",sendBuf)==0) { return; } else { printf("输入有误,请重新选择\n"); break; } } } else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } }else if (strcmp("4", sendBuf) == 0) { Sleep(2000); system("cls"); printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { fflush(stdin); //清空缓存区 checkList(); return; } else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } }else if (strcmp("5", sendBuf) == 0) {//删除文件 Sleep(2000); system("cls"); printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { fflush(stdin); //清空缓存区 delfile(); return; } else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } }else if(strcmp("6", sendBuf) == 0) {//猜数字游戏 Sleep(2000); system("cls"); //清屏 printf("等待服务器的响应......\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(strcmp("Y",recvBuf)==0 || strcmp("y",recvBuf)==0) { //recvWords(); testNum(); return; }else{ printf("recvBuf:%s", recvBuf); printf("服务器没有接受你的本次请求!\n"); printf("请重新发送请求\n"); return; } }else if (strcmp("0", sendBuf) == 0) { exit(0); } else{ printf("请选择正确的编号\n"); break; } } } //检测输入的ip合法性 int rightIP(char ip_address[15]) { int i,j,k=0; int intaddress[4]; //变成整型的ip地址 char charaddress[3]; //原ip地址 for (i=0;i<=3;i++) { for (j=0;j<=3;j++) { if (ip_address[k] == '.' || ip_address[k] == '\0') { k++; intaddress[i]=atoi(charaddress); break; } charaddress[j]=ip_address[k++]; } charaddress[0]=NULL; charaddress[1]=NULL; charaddress[2]=NULL; } i=0; while (i<4) { if (intaddress[i]>255) { printf("输入非法ip,请重新输入\n"); return -1; } i++; } if (intaddress[0]!=127||intaddress[1]!=0||intaddress[2]!=0||intaddress[3]!=1) { printf("对不起,能力有限~只能输入127.0.0.1\n"); return -1; } } //猜数字小游戏 int testNum(){ printf("输入你要猜的数字!\n"); int num,answer; fflush(stdin); gets(sendBuf); send(sockClient,sendBuf,sizeof(sendBuf),0); recv(sockClient,recvBuf,sizeof(sendBuf),0); num=recvBuf[0]; answer=recvBuf[1]; if(answer==1){ printf("猜对了!\n"); }else{ printf("猜错了!,答案是%d\n",num); } Sleep(2000); return 0; } //聊天功能 void recvWords(){ fflush(stdin); //清空缓存区 printf("开始聊天!输入exit退出!\n"); while(1) { printf("client:\n"); fflush(stdin); gets(sendBuf); send(sockClient,sendBuf,sizeof(sendBuf),0); if(!strcmp("exit",sendBuf)){ printf("退出聊天程序!\n"); break; } recv(sockClient,recvBuf,sizeof(sendBuf),0); if(strcmp("exit",recvBuf)==0) { Sleep(2000); printf("服务器已退出聊天程序!\n"); printf("重新发送请求\n"); break; } printf("\nserver:\n%s\n\n",recvBuf); } } //询问是否返回主菜单 void inquire() { printf("\n-----是否返回主菜单,Y/y N/n----- \n"); getchar(); switch(getchar()){ case 'Y': case 'y': sendRequest(); break; case 'N': case 'n': exit(0);break; default: sendRequest(); break; } } //接收文件 int recvFile(){ int ret; FILE *fp; long file_size = 0; //文件大小 int recv_sum = 0; //当前接收文件长度 int current = 0; //进度条长度 int progress = 50; //统计接受大小 char sendBuf[BUFSIZE],recvBuf[BUFSIZE],filename[512]; //接收文件确认信息 memset(recvBuf,0,sizeof(recvBuf)); ret=recv(sockClient,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret) { return -1; } else if(strcmp(recvBuf,"ERROR") == 0) { printf("未接收到文件\n"); return -1; } printf("成功接收服务端端发来的文件名: %s\n",recvBuf); //再次发送确认 memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,recvBuf); //send()发送数据 0表示正常发送数据 ,第三个是即将发送的缓冲区字符数 ret=send(sockClient,sendBuf,strlen(sendBuf),0); if (SOCKET_ERROR==ret) { return -1; } //保存文件 printf("请输入你希望保存的文件名(带扩展名)\n"); scanf("%s",filename); fp=fopen(filename,"wb"); if (NULL==fp) { return -3; } memset(recvBuf,0,sizeof(recvBuf)); //再接收文件的长度信息 ret=recv(sockClient,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret) { return -4; } printf("成功接收客户端发来的文件长度: %s\n",recvBuf); file_size = strtol(recvBuf, NULL, 10); //文件长度赋给一个长整型 printf("文件长度 :%ld\n", file_size); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,recvBuf); ret=send(sockClient,sendBuf,strlen(sendBuf),0); if (SOCKET_ERROR==ret) { return -5; } memset(recvBuf,0,sizeof(recvBuf)); while((ret = recv(sockClient,recvBuf,SIZE,0))) { if(ret<0) { printf("####L(%d) current length < 0 !\n", __LINE__); fclose(fp); exit(1); } int write_ret = fwrite(recvBuf, sizeof(char), ret, fp); //写文件 if(write_ret < ret) { printf("####L(%d) file:%s write failed write_length %d <length %d!\n", __LINE__, filename, write_ret, ret); fclose(fp); exit(1); } memset(recvBuf,0,sizeof(recvBuf)); recv_sum += ret; //printf("\nrecv_sum[%ld] ...####\n",recv_sum); current = recv_sum / (file_size / progress); printf("\r"); putchar('['); for (int i = 0; i < progress; i++) { putchar(i < current ? '>' : ' '); // 输出> 或者 ' ' } putchar(']'); printf(" %8ld/%ld %6.2f%%", recv_sum, file_size, (float)recv_sum / file_size * 100); if(recv_sum == file_size) { //接收完成 printf("\n####L(%d) recv file finished ...####\n", __LINE__); break; } else if(recv_sum > file_size) { printf("\n####L(%d) recv file err recv_sum[%ld] ...####\n", __LINE__, recv_sum); break; } Sleep(10); } fclose(fp); Sleep(2000); //睡眠等待2秒 inquire(); return 0; } //删除文件 int delfile(){ char filename[1024]; int filenum=0,i=0, ret; memset(recvBuf,0,sizeof(recvBuf)); printf(" filename\n"); while(recv(sockClient,recvBuf,sizeof(recvBuf),0) != -1) { if(strcmp(recvBuf, "OK") == 0) break; memcpy(&listfile[i],recvBuf,sizeof(LS)); printf("序号[%d] %s\n",i+1, listfile[i].name); memset(recvBuf,0,sizeof(recvBuf)); i++; Sleep(0.01); } filenum=i; printf("\n文件有%d个:\n",filenum); char c; printf("\n是否需要删除某个文件 Y/N y/n:"); c = getchar(); if(c == 'Y' || c == 'y') { printf("\n请选择你要删除的文件序号:\n"); scanf("%d", &i); strcpy(filename,listfile[i-1].name); printf("选择的文件名为:%s\n", filename); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,filename); Sleep(100); ret=send(sockClient,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { printf("发送文件名失败!"); return -1; } printf("发送文件名成功!\n"); recv(sockClient,recvBuf,sizeof(recvBuf),0); if(!strcmp(recvBuf, "OK")){ printf("删除文件成功!\n"); } Sleep(1000); } else { strcpy(sendBuf, "NOT"); send(sockClient,sendBuf,strlen(sendBuf)+1,0); Sleep(2000); inquire(); } return 0; } //查看服务器端文件列表 int checkList(){ char filename[1024]; int filenum=0,i=0, ret; memset(recvBuf,0,sizeof(recvBuf)); printf(" filename\n"); while(recv(sockClient,recvBuf,sizeof(recvBuf),0) != -1) { if(strcmp(recvBuf, "OK") == 0) break; memcpy(&listfile[i],recvBuf,sizeof(LS)); printf("序号[%d] %s\n",i+1, listfile[i].name); memset(recvBuf,0,sizeof(recvBuf)); i++; Sleep(0.01); } filenum=i; printf("\n文件有%d个:\n",filenum); char c; printf("\n是否需要下载 Y/N y/n:"); c = getchar(); if(c == 'Y' || c == 'y') { printf("\n请选择你要下载的文件序号:\n"); scanf("%d", &i); strcpy(filename,listfile[i-1].name); printf("选择的文件名为:%s\n", filename); memset(sendBuf,0,sizeof(sendBuf)); strcpy(sendBuf,filename); Sleep(100); ret=send(sockClient,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { printf("发送文件名失败!"); return -1; } printf("发送文件名成功!\n"); recvFile(); } else { strcpy(sendBuf, "NOT"); send(sockClient,sendBuf,strlen(sendBuf)+1,0); Sleep(2000); inquire(); } return 0; } //发送文件 int sendFile(){ char filename[512]; int ret,cnt,len1,lenlast; printf("\n请输入你需要传送的文件名,带扩展名\n"); scanf("%s",filename); FILE *fp; int totlen; int file_block_length; int count=0; //发送的次数 int send_sum = 0; //当前已发送文件长度 int current = 0; //进度条长度 int progress = 50; //统计接受大小 fp=fopen(filename,"rb"); while(fp==NULL) { printf("open file error\n"); printf("\n请输入你需要传送的文件名,带扩展名\n"); scanf("%s",filename); fp=fopen(filename,"rb"); } memset(sendBuf,0,sizeof(sendBuf)); //设置流 stream 的文件位置为给定的偏移 offset ,相当于定位到文件尾 fseek(fp,0,SEEK_END); //函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。相当得到文件大小 */ totlen=ftell(fp); printf("文件%s的长度为%d字节\n",filename,totlen); strcpy(sendBuf,filename); //向服务器发送文件名 ret=send(sockClient,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { return -1; } memset(recvBuf,0,sizeof(recvBuf)); //收到服务器发回来的文件名确定信息 ret=recv(sockClient,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) ) { return -1; } printf("向服务器发送文件名成功\n"); memset(sendBuf,0,sizeof(sendBuf)); //将文件大小长度 转换成字符串存入sendBuf 指向的内存空间 itoa(totlen,sendBuf,10); //给服务器发送文件长度 ret=send(sockClient,sendBuf,strlen(sendBuf)+1,0); if (SOCKET_ERROR==ret) { return -1; } memset(recvBuf,0,sizeof(recvBuf)); ret=recv(sockClient,recvBuf,sizeof(recvBuf),0); if (SOCKET_ERROR==ret|| (strcmp(sendBuf,recvBuf)!=0) ) { return -1; } printf("向服务器发送文件长度成功\n"); cnt=totlen/SIZE; len1=SIZE; if (totlen%SIZE) { lenlast=totlen-cnt*SIZE; cnt=cnt+1; } printf("\n\n文件长度为%d字节,\n每次传送%d字节,\n需要分%d次传送\n", totlen,SIZE,cnt); //重新指向文件头 rewind(fp); //读取文件指定大小元素,且元素个数 Sleep(1000); while(!feof(fp)) { //file_block_length = fread(sendBuf,SIZE,1,fp); file_block_length = fread(sendBuf, sizeof(char), SIZE, fp); send_sum += file_block_length; //累计接收文件大小 current = send_sum / (totlen / progress); //计算当前进度 printf("\r"); //光标回车 printf("["); for (int i = 0; i < progress; i++) { putchar(i < current ? '=' : '+'); } printf("]"); printf(" %8ldKB/%ldKB %6.2f%%", send_sum, totlen, (float)send_sum / totlen * 100); if(file_block_length < SIZE) { int rest_length = totlen-count*SIZE; //printf("\n剩余字符%d\n", rest_length); if(send(sockClient,sendBuf,rest_length,0) < 0) { printf("####L(%d) send file:%s failed\n", __LINE__, filename); break; } } else if(send(sockClient,sendBuf,SIZE,0) < 0) { printf("####L(%d) send file:%s failed\n", __LINE__, filename); break; } memset(sendBuf,0,sizeof(sendBuf)); count++; } printf("\n这个程序传送了%d次\n\n", count); fclose(fp); Sleep(2000); //inquire(); return 0; }这个程序做下来还是有些小bug,但是如果只是传输文件的话,已经是够了的