回射程序3(客户端)——客户服务器不定长接收数据

论坛 期权论坛 脚本     
匿名技术用户   2021-1-13 06:21   11   0

又是一个回射程序!!!!

毕竟还是一只小菜鸟,多练练,多写写没有坏处滴!

这次的回射程序思路如下:


客户端和服务器都使用了新的函数recvvl来接收数据了!!这是一个自己编写的函数,主要作用是接收不定长的数据。

整个程序的设计思路是这样的:

客户端首先将消息体的长度发送给服务器,再将消息体发送给服务器。

在服务器端先接收到消息体的长度,紧接着根据该长度接收相应的数据。

虽然上面接收数据看上去要用两步,但是我们把它放在同一个函数中了!

该函数的实现需要调用前面编写的recvn函数。其实现如下:

int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen)
{
 int iResult;//存储单次recvn操作的返回值
 unsigned int reclen; //用于存储报文头部存储的长度信息
 //获取接收报文长度信息
 iResult = recvn(s, ( char * )&reclen, sizeof( unsigned int ));
 //printf("reclen:%d\n",reclen);
 if ( iResult !=sizeof ( unsigned int )) {
  //如果长度字段在接收时没有返回一个整型数据就返回(连接关闭)或-1(发生错误)
  if ( iResult == -1 ) {
   printf("接收发生错误: %d\n", WSAGetLastError());
   return -1;
  }
  else {
   printf("连接关闭\n");
   return 0;
  }
 }
 //转换网络字节顺序到主机字节顺序
 reclen = ntohl( reclen );

 if ( reclen > recvbuflen ) {
  //如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误
  while ( reclen > 0){
   iResult = recvn( s, recvbuf, recvbuflen );
   if ( iResult != recvbuflen ) {
    //如果变长消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
    if ( iResult == -1 ) {
     printf("接收发生错误: %d\n", WSAGetLastError());
     return -1;
    }
    else {
     printf("连接关闭\n");
     return 0;
    }
   }
   reclen -= recvbuflen;
   //处理最后一段数据长度
   if ( reclen < recvbuflen )
    recvbuflen = reclen;
  }
  printf("可变长度的消息超出预分配的接收缓存\r\n");
  return -1;
 }
 //接收可变长消息
 iResult = recvn( s, recvbuf, reclen );
 if ( iResult != reclen ){
  //如果消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
  if ( iResult == -1 ) {
   printf("接收发生错误: %d\n", WSAGetLastError());
   return -1;
  }
  else {
   printf("连接关闭\n");
   return 0;
  }
 }
 return iResult;
}

函数参数说明:SOCKET s 连接套接字

char * recvbuf 接收缓存

unsigned int recvbuflen 缓存区的大小

值得注意的是,在接收过程中,需要将接收到的数据长度信息进行字节序的转换!!

//转换网络字节顺序到主机字节顺序
 reclen = ntohl( reclen );

在发送数据长度之前,需要进行htonl的转换!!

下面贴上客户端的代码:

// 回显客户端3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#pragma  comment(lib,"wsock32.lib")


#define  MAXSIZE 100

//函数声明
int recvn(SOCKET s, char * recvbuf, unsigned int fixedlen);
int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen);


int _tmain(int argc, _TCHAR* argv[])
{
 //初始化WinSock
 WSADATA wsaData;
 int ret = WSAStartup(MAKEWORD(2,2),&wsaData);
 if(ret != 0)
 {
  printf("WSAStratup failed!code:%d\n",WSAGetLastError());
  return -1;
 }
 if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
 {
  WSACleanup();
  printf("Invaild WinSock Version\n");
  return -1;
 }
 //建立客户端套接字
 SOCKET sockclient;
 sockclient = socket(AF_INET,SOCK_STREAM,0);
 if(sockclient==INVALID_SOCKET)
 {
  WSACleanup();
  printf("socket() failed!code:%d\n",WSAGetLastError());
  return -1;
 }
 //服务器地址信息
 struct sockaddr_in saServer;
 saServer.sin_family = AF_INET;
 saServer.sin_port=htons(6000);
 saServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
 //连接服务器
 ret = connect(sockclient,(sockaddr*)&saServer,sizeof(saServer));
 if(ret == SOCKET_ERROR)
 {
  printf("connect() failed!code:%d\n",WSAGetLastError());
  closesocket(sockclient);
  WSACleanup();
  return -1;
 }
 else
  printf("connect successed\n");

 //向服务器发送数据
 //首先发送定长的消息声明本次传输的消息长度
 //再发送变长的消息体
 unsigned int slen = 0;
 unsigned int buflen = MAXSIZE;
 char buff[MAXSIZE];  //发送缓存
 char recvbuff[MAXSIZE]; //接收缓存
 //memset(buff, 0 , MAXSIZE);
 while (TRUE) 
 {
  memset(recvbuff,0,MAXSIZE);
  printf("Please input a string to send:\n");
  scanf("%s",buff);
  if(strcmp(buff,"q")==0)
   break;
  slen = (unsigned int)strlen(buff);
  slen = htonl(slen);
  if(send(sockclient, (char*)&slen, sizeof(unsigned int), 0) <= 0) 
  {
   printf("send failed !code:%d\n",WSAGetLastError());
   closesocket(sockclient);
   WSACleanup();
   return -1;
  }
  if(send(sockclient, buff, strlen(buff), 0) <= 0) 
  {
   printf("send failed !code:%d\n",WSAGetLastError());
   closesocket(sockclient);
   WSACleanup();
   return -1;
  }
  ret = recvvl(sockclient,recvbuff,buflen);
  if(ret==SOCKET_ERROR)
  {
   int nErrCode = WSAGetLastError();//错误代码
   if (WSAENOTCONN == nErrCode)
   {
    printf("The socket is not connected!\n");

   }else if(WSAESHUTDOWN == nErrCode)
   {
    printf("The socket has been shut down!\n");

   }else if (WSAETIMEDOUT == nErrCode)
   {
    printf("The connection has been dropped!\n");       
   }else if (WSAECONNRESET == nErrCode)
   {
    printf("The virtual circuit was reset by the remote side!\n");
   }else{} 
   closesocket(sockclient);
   WSACleanup();
   return -1;
  }
  //打印收到的回显字符串
  printf("%s\n",recvbuff);
 }
 closesocket(sockclient);
 WSACleanup();
 return 0;
}


//指定长度接收
int recvn(SOCKET s, char * recvbuf, unsigned int fixedlen)
{
 int iResult;    //存储单次recv操作的返回值
 int cnt;         //用于统计相对于固定长度,剩余多少字节尚未接收
 cnt = fixedlen;
 while ( cnt > 0 ) {
  iResult = recv(s, recvbuf, cnt, 0);
  if ( iResult < 0 ){
   //数据接收出现错误,返回失败
   printf("接收发生错误: %d\n", WSAGetLastError());
   return -1;
  }
  if ( iResult == 0 ){
   //对方关闭连接,返回已接收到的小于fixedlen的字节数
   printf("连接关闭\n");
   return fixedlen - cnt;
  }
  //printf("接收到的字节数: %d\n", iResult);
  //接收缓存指针向后移动
  recvbuf +=iResult;
  //更新cnt值
  cnt -=iResult;         
 }
 return fixedlen;
}


int recvvl(SOCKET s, char * recvbuf, unsigned int recvbuflen)
{
 int iResult;//存储单次recvn操作的返回值
 unsigned int reclen; //用于存储报文头部存储的长度信息
 //获取接收报文长度信息
 iResult = recvn(s, ( char * )&reclen, sizeof( unsigned int ));
 //printf("reclen:%d\n",reclen);
 if ( iResult !=sizeof ( unsigned int )) {
  //如果长度字段在接收时没有返回一个整型数据就返回(连接关闭)或-1(发生错误)
  if ( iResult == -1 ) {
   printf("接收发生错误: %d\n", WSAGetLastError());
   return -1;
  }
  else {
   printf("连接关闭\n");
   return 0;
  }
 }
 //转换网络字节顺序到主机字节顺序
 reclen = ntohl( reclen );

 if ( reclen > recvbuflen ) {
  //如果recvbuf没有足够的空间存储变长消息,则接收该消息并丢弃,返回错误
  while ( reclen > 0){
   iResult = recvn( s, recvbuf, recvbuflen );
   if ( iResult != recvbuflen ) {
    //如果变长消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
    if ( iResult == -1 ) {
     printf("接收发生错误: %d\n", WSAGetLastError());
     return -1;
    }
    else {
     printf("连接关闭\n");
     return 0;
    }
   }
   reclen -= recvbuflen;
   //处理最后一段数据长度
   if ( reclen < recvbuflen )
    recvbuflen = reclen;
  }
  printf("可变长度的消息超出预分配的接收缓存\r\n");
  return -1;
 }
 //接收可变长消息
 iResult = recvn( s, recvbuf, reclen );
 if ( iResult != reclen ){
  //如果消息在接收时没有返回足够的数据就返回(连接关闭)或-1(发生错误)
  if ( iResult == -1 ) {
   printf("接收发生错误: %d\n", WSAGetLastError());
   return -1;
  }
  else {
   printf("连接关闭\n");
   return 0;
  }
 }
 return iResult;
}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP