项目简介
本程序的文件传输系统的实现包含服务端模块、客户端模块,使用流式套接字。在设计时设计客户端和服务端两个界面时,客户端的所有信息发往服务器端,再由服务器端进行消息的分析处理并做出相应的操作,服务器端时所有信息的中心。本程序可实现互相聊天、互相传送、以及查询删除文件。
-
系统界面
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,但是如果只是传输文件的话,已经是够了的