18,773
社区成员
发帖
与我相关
我的任务
分享
void SendFile(int socketFd,Connection*conn)
{
//接收客户端发来的文件请求
char recvMsg[BUFFER_SIZE];
ReceiveMessage(socketFd,recvMsg);
string fileName=recvMsg;
cout<<"Client request file: "<<fileName<<endl;
//连接数据库,生成需要发送的文件
//CreateDbXml(conn,fileName);
//获取文件长度,并发送
unsigned long fileLen=get_file_size(recvMsg);
char buffer[BUFFER_SIZE];
bzero(buffer,sizeof(buffer));
snprintf(buffer,sizeof(buffer),"%u",fileLen);
SendMessage(socketFd,buffer,strlen(buffer));
//打开文件
FILE * fp=fopen(recvMsg,"r");
if(fp==NULL)
{
cout<<"File "<<fileName<<" not fount!"<<endl;
}
//发送文件
bzero(buffer,sizeof(buffer));
int file_block_length=0;
while((file_block_length=fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
SendMessage(socketFd,buffer,file_block_length);
cout<<buffer;
bzero(buffer,sizeof(buffer));
usleep(50000);//如果去掉此行代码,或者usleep()函数的参数过小,监控端都会出现数据丢失的情况
}
fclose(fp);
cout<<"File "<<fileName<<" transfer finished!"<<endl;
}
//为了避免数据的粘粘问题,发送数据时先发送数据长度,再发送数据
int SendMessage(int socketFd,char * sendBuffer,int sendLen)
{
char len[5];
snprintf(len,sizeof(len),"%04d",sendLen);
//printf("len:%s\n",len);
if(send(socketFd,len,sizeof(len)-1,0)<0)
{
perror("send :");
return -1;
}
int sendRecv;
if((sendRecv=send(socketFd,sendBuffer,sendLen,0))<0)
{
perror("send sendBuffer:");
return -1;
}
return sendRecv;
}
//为了避免数据的沾粘问题,接收数据时,先接收数据长度,再接收数据
int ReceiveMessage(int sockFd,char recvMsg[])
{
//获取接收数据的长度
char msgSize[5];
int sizeLen=sizeof(msgSize);
if(recv(sockFd,msgSize,sizeLen-1,0)<0)
{
perror("recv:");
}
msgSize[sizeLen-1]='\0';
int msgLen=atoi(msgSize);
int recvLen;
if((recvLen=recv(sockFd,recvMsg,msgLen,0))<0)
{
perror("recv:");
}
recvMsg[msgLen]='\0';
return recvLen;
}
/// <summary>
/// 发送带有数据长度的数据包
/// </summary>
/// <param name="s">发送数据用的套接字</param>
/// <param name="msg">发送数据的缓冲区</param>
/// <returns>发送已经发送的数据个数</returns>
public static int SendMessage(Socket s, byte[] msg)
{
int sendLen;
byte[] msgsize = new byte[4];
msgsize = Encoding.UTF8.GetBytes(msg.Length.ToString("0000"));
sendLen = s.Send(msgsize);
//判断如果要发送的数据长度为零,则直接返回0
if (sendLen == 0)
{
return 0;
}
int offset = 0;//用来记录一个数据包已经发送的字节数
int dataLeft = sendLen;//用来记录一个数据包中还有多少字节的数据没有发送
int rstLen = 0;//用来记录单次发送数据的字节数
while (dataLeft>0)
{
rstLen = s.Send(msg, 0, msg.Length, SocketFlags.None);
offset += rstLen;
dataLeft -= rstLen;
}
return offset;
} /// <summary>
/// 接收带有数据长度的数据包
/// </summary>
/// <param name="s">接收数据用的套接字</param>
/// <param name="msg">存放接收数据的数组,因为要在函数中分配与数据包长度相同的缓冲区大小,所以此处要用到引用类型</param>
/// <returns>返回0表示没有接收到数据,大于零的值表示正确接收到的数据个数</returns>
public static int ReceiveMessage(Socket s, ref byte[] msg)
{
int recvLen = -1; //接收数据时返回的数据长度
byte[] msgLen = new byte[4];
recvLen = s.Receive(msgLen, 0, 4, SocketFlags.None);
//如果接收到的数据长度为0,说明没有接收到数据,直接返回0
if (recvLen == 0)
{
return 0;
}
//获得数据包的长度
int msgLenth = Convert.ToInt32(Encoding.UTF8.GetString(msgLen));
//用来记录此数据包中要有多少数据没有接收
int dataLeft = msgLenth;
//用来记录此数据包中已经接收了多收数据
int offset = 0;
//为接收缓冲区分配与数据长度相对于的存储空间
msg = new byte[msgLenth];
while (dataLeft > 0)
{
recvLen = s.Receive(msg, offset, dataLeft, SocketFlags.None);
if (recvLen==0)
{
return 0;
}
offset += recvLen;
dataLeft -= recvLen;
}
return offset;
}
int SendMessage(int socketFd,char * sendBuffer,int sendLen)
{
//发送数据的长度
char len[5];
snprintf(len,sizeof(len),"%04d",sendLen);
if(send(socketFd,len,sizeof(len)-1,0)<0)
{
perror("send :");
return -1;
}
//发送数据
int sendRecv;
int offset=0;//数据包中已经发送的字节数
int dataLeft=sendLen;//数据包中已经发送的字节数
int rstLen=0; //用来保存一次发送数据所发送的字节数
while(dataLeft>0)
{
if((rstLen=send(socketFd,sendBuffer,sendLen,0))<0)
{
perror("send sendBuffer:");
return -1;
}
offset+=rstLen;
dataLeft-=rstLen;
}
return offset;
}
int ReceiveMessage(int sockFd,char recvMsg[])
{
//获取接收数据的长度
char msgSize[5];
int sizeLen=sizeof(msgSize);
if(recv(sockFd,msgSize,sizeLen-1,0)<0)
{
perror("recv:");
}
msgSize[sizeLen-1]='\0';
int msgLen=atoi(msgSize);
int recvLen;
int offset=0;
int dataLeft=msgLen;
int rstLen=0;
while(dataLeft>0)
{
if((rstLen=recv(sockFd,recvMsg,msgLen,0))<0)
{
perror("recv:");
}
offset+=rstLen;
dataLeft-=rstLen;
}
recvMsg[msgLen]='\0';
return offset;
}
BinaryWriter bWriter = new BinaryWriter(fileStream);
byte[] recvBuffer = new byte[1024];
//int rstLen = GlobalFunction.ReceiveMessage(sock, ref recvBuffer);
int rstLen = sock.Receive(recvBuffer);
bWriter.Write(recvBuffer);
//bWriter.Flush();
while (rstLen < iFileLen)
{
//int tempLen = GlobalFunction.ReceiveMessage(sock, ref recvBuffer);
byte[] recBuffer = new byte[1024];
int tempLen = sock.Receive(recBuffer);
bWriter.Write(recBuffer,0,tempLen);
Console.WriteLine(tempLen);
//bWriter.Flush();
rstLen += tempLen;
}
这样,在发送端不设置sleep函数,接收端也能够完整的接收数据。
但是,我仍然不明白为什么利用自定义的ReceiveMessage函数会有问题,难道是我这个函数写的有问题?
但是我平时用的时候没有问题啊,难道跟数据量有关?/////////////利用二进制文件写入方式,接收到什么字节数据,就写入什么字节数据/////////
BinaryWriter bWriter = new BinaryWriter(fileStream);
byte[] recvBuffer = new byte[2048];
//int rstLen = GlobalFunction.ReceiveMessage(sock, ref recvBuffer);
int rstLen = sock.Receive(recvBuffer);
bWriter.Write(recvBuffer);
bWriter.Flush();
while (rstLen < iFileLen)
{
//int tempLen = GlobalFunction.ReceiveMessage(sock, ref recvBuffer);
int tempLen = sock.Receive(recvBuffer);
bWriter.Write(recvBuffer);
bWriter.Flush();
rstLen += tempLen;
}
利用的是BinaryWriter进行二进制的文件写入,这样我个人感觉就不涉及到编码的问题了。
请问是不是C#中套接字的Receive函数在socket缓冲区中取数据时出现了问题?