当前位置:网站首页>基于TCP/IP协议的网络通信实例——文件传输
基于TCP/IP协议的网络通信实例——文件传输
2022-04-23 07:15:00 【欧特_Glodon】
一、服务端代码:MyServer.cpp
// MyServer.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<stdlib.h>
#include<winsock2.h>//引用头文件
#pragma comment(lib,"ws2_32.lib")//引用库文件
//最大连接数
#define g_MaxConnect 20
int g_Connect = 0;
struct sock_params
{
SOCKET hsock;
int nSockIndex;
};
//线程实现函数
DWORD WINAPI threadpro(LPVOID pParam)
{
sock_params* sockPam = (sock_params*)pParam;
SOCKET hsock = sockPam->hsock;
int nSockIndex = sockPam->nSockIndex;
char aIndex[4];
_itoa_s(nSockIndex, aIndex, 10);
char buffer[1024];
char sendBuffer[1024];
if(hsock != INVALID_SOCKET)
{
cout<<"客户端 "<< nSockIndex << " 加入服务器!" <<endl;
}
// 设定接收缓冲区大小
int nRecvBufLen = 1024* 1024; //默认设置为1024K
int nStaus = setsockopt(hsock ,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBufLen,sizeof(int));
if (nStaus == SOCKET_ERROR)
{
hcDebugLog(_T("ZLY:设定接收缓冲区大小失败!"));
}
// 设定发送缓冲区大小
int nSendBufLen = 1024* 1024; //默认设置为1024K
nStaus = setsockopt(hsock ,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBufLen,sizeof(int));
if (nStaus == SOCKET_ERROR)
{
hcDebugLog(_T("ZLY:设定发送缓冲区大小失败!"));
}
//循环接收发送的文件内容
int nErrorNum = 0;
while (1)
{
// 服务端接收文件名称数据
FileName fn;
memset(&fn, 0, sizeof(FileName));
int nRecvSize = recv(clientSocket, (char*)&fn, sizeof(fn), 0);
if (sizeof(fn) != nRecvSize)
{
if (nRecvSize != 0 && nErrorNum <= MAX_ERROR_NUM)
{
printf("接收文件名称失败!错误码:%d\n", WSAGetLastError());
nErrorNum++;
continue;
}
else
{
break;
}
}
char chPath[_MAX_PATH];
memset(chPath, 0, sizeof(char)*_MAX_PATH);
strcpy_s(chPath, sizeof(chPath), fn.serverDir);
int len = strlen(chPath);
if (chPath[len - 1] != '\\')
{
chPath[len] = '\\';
len++;
}
strcat_s(chPath, fn.dir);
len = strlen(chPath);
if (chPath[len - 1] != '\\')
{
chPath[len] = '\\';
len++;
}
// 创建对应目录
g_lock.Lock();
CreateDir(chPath);
g_lock.UnLock();
strcat_s(chPath, fn.Fname);
// 创建文件
FILE* fp = NULL;
errno_t err = fopen_s(&fp, chPath, "wb");
if (err != 0)
{
printf("创建文件失败:%s, 错误码:%d\n", chPath, GetLastError());
continue;
}
// 服务端接收文件长度
long long nSize;
nRecvSize = recv(clientSocket, (char*)&nSize, sizeof(nSize), 0);
if (sizeof(nSize) != nRecvSize)
{
if (fp)
{
fclose(fp);
fp = NULL;
}
if (nRecvSize != 0 && nErrorNum <= MAX_ERROR_NUM)
{
printf("接收文件长度失败!错误码:%d\n", WSAGetLastError());
nErrorNum++;
continue;
}
else
{
break;
}
}
// 循环接受文件内容
int num;
char buff[MAX_PACK_SIZE];
while (nSize > 0)
{
if (nSize >= MAX_PACK_SIZE)
{
num = recv(clientSocket, buff, MAX_PACK_SIZE, 0);
}
else
{
num = recv(clientSocket, buff, nSize, 0);
}
fwrite(buff, (int)num, 1, fp);
nSize -= num;
memset(buff, 0, sizeof(char)*MAX_PACK_SIZE); //将buff清空
}
// 关闭文件
if (fp)
{
fclose(fp);
fp = NULL;
}
// 发送文件接受成功状态
int nRecvStatus = 0;
send(clientSocket, (char*)&nRecvStatus, sizeof(int), 0);
}
return 0;
}
//主函数
void main()
{
WSADATA wsd;//定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd);
SOCKET m_SockServer;
sockaddr_in serveraddr;
sockaddr_in serveraddrfrom;
SOCKET m_Server[g_MaxConnect];
serveraddr.sin_family = AF_INET;//设置服务器地址
serveraddr.sin_port = htons(4600);//设置端口号
serveraddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
m_SockServer = socket(AF_INET,SOCK_STREAM,0);
int nStatus = bind(m_SockServer,(sockaddr*)&serveraddr,sizeof(serveraddr));
if (nStatus == 0)
{
cout << "服务端启动成功!" <<endl;
}
else
{
cout << "服务端启动失败!" <<endl;
return;
}
int iLisRet = 0;
int len = sizeof(sockaddr);
while(1)
{
iLisRet = listen(m_SockServer,0);//进行监听
m_Server[g_Connect] = accept(m_SockServer,(sockaddr*)&serveraddrfrom,&len);
//同意连接
if(m_Server[g_Connect] != INVALID_SOCKET)
{
if(g_Connect > g_MaxConnect-1)
{
char WarnBuf[50]="客户端连接个数:超限!";
int ires = send(m_Server[g_Connect],WarnBuf,sizeof(WarnBuf),0);
}
else
{
char cIndex[4];
_itoa_s(g_Connect, cIndex, 10);
char buf[50]="你的服务端ID: ";
strcat_s(buf, cIndex);
int ires = send(m_Server[g_Connect],buf,sizeof(buf),0);//发送字符过去
//cout << buf <<endl;
HANDLE m_Handel; //线程句柄
DWORD nThreadId=0; //线程ID
sock_params sockPam;
sockPam.hsock = m_Server[g_Connect];
sockPam.nSockIndex = g_Connect;
m_Handel = (HANDLE)::CreateThread(NULL,0,threadpro,&sockPam,0,&nThreadId);
CloseHandle(m_Handel);
}
++g_Connect;
}
}
WSACleanup();
}
二、客户端:MyClient.cpp
// MyClient.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdlib.h>
#include<stdio.h>
#include"winsock2.h"
#include<time.h>
#pragma comment(lib,"ws2_32.lib")
void main()
{
WSADATA wsd;//定义WSADATA对象
WSAStartup(MAKEWORD(2,2),&wsd);
SOCKET m_SockClient;
sockaddr_in clientaddr;
clientaddr.sin_family = AF_INET; //设置服务器地址
clientaddr.sin_port = htons(4600); //设置服务器端口号
clientaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
m_SockClient = socket(AF_INET,SOCK_STREAM,0);
if (m_SockClient == INVALID_SOCKET)
{
printf("Sock 初始化失败: %d\n", WSAGetLastError());
WSACleanup();
return ;
}
// 获取发送缓冲区和接送缓冲区大小
{
int optlen = 0;
int optval = 0;
optlen = sizeof(optval);
getsockopt(m_SockClient, SOL_SOCKET, SO_SNDBUF, (char*)&optval, &optlen);
printf("send buf len is %d\n",optval); //64位 默认发送缓冲区64k
getsockopt(m_SockClient, SOL_SOCKET, SO_RCVBUF, (char*)&optval, &optlen);
printf("Recv buf len is %d\n",optval); //64位 默认接收缓冲区64k
}
// 设定接收缓冲区大小
int nRecvBufLen = 1024* 1024; //默认设置为1024K
int nStaus = setsockopt(pSocketData->clientSocket,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBufLen,sizeof(int));
if (nStaus == SOCKET_ERROR)
{
hcDebugLog(_T("ZLY:设定接收缓冲区大小失败!"));
}
// 设定发送缓冲区大小
int nSendBufLen = 1024* 1024; //默认设置为1024K
nStaus = setsockopt(pSocketData->clientSocket,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBufLen,sizeof(int));
if (nStaus == SOCKET_ERROR)
{
hcDebugLog(_T("ZLY:设定发送缓冲区大小失败!"));
}
int nSuccess = connect(m_SockClient,(sockaddr*)&clientaddr,sizeof(clientaddr));//连接超时
if (nSuccess == 0)
{
cout<<"连接服务器成功!"<<endl;
}
else
{
cout<<"连接服务器失败!"<<endl;
return;
}
char buffer[1024];
char inBuf[1024];
int num = 0;
num = recv(m_SockClient,buffer,1024,0);//阻塞
if(num > 0)
{
cout << /*"Receive from server:"<<*/ buffer<<endl;
char* pResult = strstr(buffer, "超限");
if (pResult != NULL)
{
cout<<"服务器连接个数超限,不可用!"<<endl;
system("pause");
return;
}
//传递文件名称
char filename[256];
FILE* m_fp;
errno_t err = fopen_s(&m_fp, filename, "rb");
if (err != 0)
{
strlog.Format(_T("文件“%s”打开失败,错误码:0x%X"), filename, GetLastError());
return -1;
}
// 读取文件名称发送
if (sizeof(filename) != send(m_sock, &filename, sizeof(filename), 0))
{
strLog.Format(_T("文件“%s”发送文件名称失败,错误码:%d。"), (LPCTSTR)CString(m_fn.Fname), WSAGetLastError());
cout << strLog <<endl;
fclose(m_fp);
m_fp = NULL;
return -1;
}
fseek(m_fp, 0, SEEK_END);
long long nSize = ftell(m_fp);
fseek(m_fp, 0, SEEK_SET);
// 获取文件长度,发送文件长度(废弃)
if (sizeof(nSize) != send(m_sock, (char*)&nSize, sizeof(nSize), 0))
{
printf(_T("发送文件长度失败,错误码:%d。"), WSAGetLastError());
fclose(m_fp);
m_fp = NULL;
return -1;
}
//发送文件
/* 循环发送多个文件貌似会出错 HANDLE hFile = CreateFile(lpszFilePath,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); TransmitFile(m_Socket,hFile,0,TRANS_FILE_LENGTH,NULL,NULL,TF_DISCONNECT); CloseHandle(hFile); */
// 循环发送文件
size_t nNum;
while (1)
{
nNum = fread(m_temp, 1, 1024*500, m_fp);
if (nNum == 0)
break;
if (nNum != send(m_sock, m_temp, (int)nNum, 0))
{
strLog.Format(_T("文件“%s”发送文件数据失败,错误码:%d。"), (LPCTSTR)CString(m_fn.Fname), WSAGetLastError());
fclose(m_fp);
m_fp = NULL;
return -1;
}
memset(m_temp, 0, sizeof(char)*1024*500);
}
// 关闭文件
fclose(m_fp);
m_fp = NULL;
//接收服务端端反馈的数据
int recv_len = recv(m_SockClient,buffer,1024,0);
if(recv_len>=0)
{
cout<< buffer <<endl;
}
}
}
版权声明
本文为[欧特_Glodon]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_37251750/article/details/121267651
边栏推荐
- 浅谈ES6尾调优化
- 情境领导者-第七章、解决绩效问题
- Mobile terminal layout (3D conversion, animation)
- 常用正则表达式
- 岛屿的个数
- Convert object to URL
- [problem solving] vs2019 solves the problem that the EXE file generated by compilation cannot be opened
- Quick rehearsal exercise
- [programming practice / embedded competition] learning record of embedded competition (I): establishment of TCP server and web interface
- 简述CPU
猜你喜欢

How to import Excel data in SQL server, 2019 Edition

Ubuntu安装Mysql并查询平均成绩

LeetCode簡單題之計算字符串的數字和

LeetCode 1611. 使整数变为 0 的最少操作次数

The whole house intelligence bet by the giant is driving the "self revolution" of Hisense, Huawei and Xiaomi

AAAI 2022 recruit speakers!!

简述CPU

Weekly leetcode - 06 array topics 7 ~ 739 ~ 50 ~ offer 62 ~ 26 ~ 189 ~ 9

欧圣电气深交所上市:市值52亿 陆为东父女为美国籍

惨了,搞坏了领导的机密文件,吐血分享备份文件的代码技巧
随机推荐
扎心了!一女子发朋友圈羡慕别人按时发工资被开除,连点赞的同事也一同被开除了...
Go语学习笔记 - 语言接口 | 从零开始Go语言
浏览器中的 Kubernetes 和 IDE | 交互式学习平台Killercoda
PHP high precision computing
Distributed service governance Nacos
Canvas learning Chapter 1
dried food! Point based: differentiable Poisson solver
[Effective Go 中文翻译] 第一篇
LeetCoed18. 四数之和
几种智能机器人室内定位方法对比
Upload labs range practice
三星,再次“西征”
华硕笔记本电脑重装系统后不能读取usb,不能上网
[Effective Go 中文翻译]函数篇
英语课小记(四)
LeetCode 1611. 使整数变为 0 的最少操作次数
每周leetcode - 06 数组专题 7~739~50~offer 62~26~189~9
Usage of databinding
谈谈那些基础但不简单的股票数据
青苹果影视系统源码 影视聚合 影视导航 影视点播网站源码