Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TCP套接字:recv()未接收完整数据_C_Sockets_Tcp - Fatal编程技术网

TCP套接字:recv()未接收完整数据

TCP套接字:recv()未接收完整数据,c,sockets,tcp,C,Sockets,Tcp,我有一个关于客户端/服务器TCP应用程序的问题 我需要它做以下事情: 传输的文件应以不超过1460字节的包发送 客户机应该询问要传输的文件名,然后连接到服务器,发送一个包含大小、要发送的包数量和文件名的结构。等待服务器发回与握手相同的结构,以检查是否接收到了所有内容。如果收到的一个相同,它将开始发送所有包。之后,再次发送struct以通知所有内容都已发送,并等待服务器响应 服务器应该等待连接,然后创建一个子节点来管理它。它应该发回包含文件信息的struct received,开始将收到的包保存

我有一个关于客户端/服务器TCP应用程序的问题

我需要它做以下事情:

  • 传输的文件应以不超过1460字节的包发送
  • 客户机应该询问要传输的文件名,然后连接到服务器,发送一个包含大小、要发送的包数量和文件名的结构。等待服务器发回与握手相同的结构,以检查是否接收到了所有内容。如果收到的一个相同,它将开始发送所有包。之后,再次发送struct以通知所有内容都已发送,并等待服务器响应
  • 服务器应该等待连接,然后创建一个子节点来管理它。它应该发回包含文件信息的struct received,开始将收到的包保存在与指示名称相同的文件中,并在收到包含struct信息的包后停止。然后检查收到的包的数量,文件大小是否与结构上指示的相同
我正在努力解决的主要问题是,在服务器中,recv()无法获取某些包中发送的所有数据。例如,我尝试使用一个大小为14.3kB的文本文件(它可以分为10个包发送,其中9个包的大小为1460字节,最后一个包的大小小于1460字节),但收到的第一个包的大小为528字节,然后是1460中的2个,然后它将完全停止接收

另一件我不知道如何做的事情是,当服务器接收到文件信息结构时,如何将其转换为字符数组

我的代码如下:

客户

#include <string.h>
#include <stdbool.h>
#include <sys/types.h>    
#include <sys/socket.h>  
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <math.h>

#define  PORT_NUM           33333  // Port number used
#define  IP_ADDR "127.0.0.1" // IP address of server1 (*** HARDWIRED ***)
#define SOCKET_PROTOCOL 0

struct infoarchivo{
   unsigned long tamanio;
   unsigned long paquetes;
   char nombrearchivo[512];} info_tx,info_rx;

bool comparar(struct infoarchivo rx, struct infoarchivo tx);

int main(int argc, char *argv[])
{

 unsigned int         client_s;        // Descriptor del socket
 struct sockaddr_in   server_addr;     // Estructura con los datos del servidor
 struct sockaddr_in   client_addr;     // Estructura con los datos del cliente
 int                  addr_len;        // Tamaño de las estructuras
 char                 buf_tx[1460];    // Buffer de 1460 bytes para los datos a transmitir
 char                 ipserver[16];
 int                  bytesrecibidos,bytesaenviar, bytestx;               // Contadores
 int                  conectado; //variable auxiliar
 char                 nombre_archivo[512];
 long tamano_archivo,paquetes_archivo;
 char respuesta[3];
 bool flag,flag2;
 FILE * fp;
 int i;

 if (argc!=2)
   {
   printf("uso: clienteUDP www.xxx.yyy.zzz\n");
   return -1; 
   }
   strncpy(ipserver,argv[1],16);
 
 client_s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
 if (client_s==-1)
   {
   perror("socket");
   return 2;
   }
 printf("Cree el descriptor del socket %d\n",client_s);
 
 server_addr.sin_family      = AF_INET;            // Familia TCP/IP
 server_addr.sin_port        = htons(PORT_NUM);    // Número de Port, htons() lo convierte al orden de la red
 
 if  (inet_aton(ipserver, &server_addr.sin_addr)==0) // cargo la estructura con la dirección IP del servidor
   {
   printf ("La dirección  IP_ADDR no es una dirección IP válida. Programa terminado\n"); 
   return 3;
   }
 addr_len = sizeof(server_addr);
  
 conectado=connect(client_s, (struct sockaddr *)&server_addr, sizeof(server_addr));
 if (conectado==-1)
   {
   perror("connect");
   return 4;
   }
    printf("El IP del servidor es: %s y el port del servidor  es %hu \n",inet_ntoa(server_addr.sin_addr),
           ntohs(server_addr.sin_port));
 do{  
   printf("Ingrese ruta completa del archivo a transmitir:\n");
   scanf("%s", nombre_archivo); /*Consigo nombre del archivo a transmitir*/
   fp = fopen(nombre_archivo,"r");
   if(fp == NULL){
       perror("Error");
   return 0;
   }
   fseek(fp, 0, SEEK_END);
   tamano_archivo = ftell(fp); /*tamano del archivo a transmitir*/
   rewind(fp);
   paquetes_archivo=ceil(tamano_archivo/1460)+1; /*cantidad de paquetes a enviar*/
   printf("%lu, %lu\n", tamano_archivo,paquetes_archivo);
   /*Envio informacion del archivo a transmitir*/
   info_tx.tamanio=tamano_archivo;
   info_tx.paquetes=paquetes_archivo;
   strcpy(info_tx.nombrearchivo,nombre_archivo);
   bytesaenviar=sizeof(info_tx);
   bytestx=send(client_s, &info_tx, bytesaenviar,0); 
   /*Espero confirmacion de lo recibido*/
   bytesrecibidos=recv(client_s, &info_rx, sizeof(info_rx), 0);
   flag = comparar(info_rx,info_tx); /*comparo las dos estructuras*/
   if(flag==true){ /*si son iguales*/
   if(paquetes_archivo>1){ /*envio archivo*/
       for(i=1;i<=paquetes_archivo-1;i++){ /*si tengo que enviar mas de 1 paquete envio n-1 de 1459 bytes*/
           fread(buf_tx,1460,1,fp);
           bytestx=send(client_s, buf_tx, bytesaenviar,0);
           printf("Envie paquete %d, que dice: %s\n",i,buf_tx);
           bzero(buf_tx,sizeof(buf_tx));
       }
   }
   fread(buf_tx,tamano_archivo-1460*(paquetes_archivo-1),1,fp); /*y un ultimo paquete de menos de 1459 bytes*/
   bytestx=send(client_s, buf_tx, bytesaenviar,0);
   printf("Envie el ultimo paquete, que dice: %s\n",buf_tx);
   /*VOLVER A ENVIAR, RECIBIR Y COMPARAR ESTRUCTURAS*/
       bytesaenviar=sizeof(info_tx);
       bytestx=send(client_s, &info_tx, bytesaenviar,0); 
   printf("Envie info del archivo\n");
       /*Espero confirmacion de lo recibido*/
       bytesrecibidos=recv(client_s, &info_rx, sizeof(info_rx), 0);
   printf("Recibí info del archivo\n");
       flag2 = comparar(info_rx,info_tx);
   printf("Compare info del archivo\n");
   if(flag2==true){
       printf("Envio finalizado con exito.\n");    
   }
   else{
       printf("%s",info_rx.nombrearchivo);
   }
   }
   else{
   printf("%s",info_rx.nombrearchivo);
   }
   fclose(fp);
   printf("¿Desea enviar otro archivo? (Si/No)\n");
   scanf("%s",respuesta);

 } while (strncmp(respuesta,"Si",2)==0); 
 
close(client_s);
printf("¡Hasta luego!\n");
return 0;
} // fin del programa    

bool comparar(struct infoarchivo rx,struct infoarchivo tx){
   if(rx.tamanio==tx.tamanio && rx.paquetes == tx.paquetes && strcmp(rx.nombrearchivo,tx.nombrearchivo)==0){
       return true;
   }
   else{
       return false;
   }
} 
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义端口号33333//使用的端口号
#定义服务器1的IP地址“127.0.0.1”//IP地址(***硬连线***)
#定义套接字\u协议0
结构信息档案{
未签名的长塔马尼奥;
未签名的长帕奎特;
字符nombrearchivo[512];}信息发送,信息接收;
布尔比较器(结构infoarchivo rx、结构infoarchivo tx);
int main(int argc,char*argv[])
{
unsigned int client_s;//描述符del套接字
服务器中的struct sockaddr\u\u addr;//服务数据的结构
客户端中的struct sockaddr\u\u addr;//客户端数据结构
int addr_len;//Tamaño de las estructuras
char buf_tx[1460];//传输数据的1460字节缓冲区
char-ipserver[16];
int bytesrecibidos,bytesaenviar,bytestx;//Contadores
int conectado;//变量辅助变量
char nombre_archivo[512];
长塔马诺·阿奇沃、帕奎特斯·阿奇沃;
char-respuesta[3];
布尔旗,flag2;
文件*fp;
int i;
如果(argc!=2)
{
printf(“uso:clientudp www.xxx.yyy.zzz\n”);
返回-1;
}
strncpy(ipserver,argv[1],16);
客户端=socket(AF\u INET、SOCK\u流、socket\u协议);
如果(客户端==-1)
{
佩罗(“插座”);
返回2;
}
printf(“Cree el描述符del套接字%d\n”,客户端);
server\u addr.sin\u family=AF\u INET;//Familia TCP/IP
server_addr.sin_port=htons(port_NUM);//Número de port,htons()是红色的
如果(inet_aton(ipserver,&server_addr.sin_addr)==0)//货物的结构与服务的设计
{
printf(“La dirección IP_ADDR no es una dirección IP válida.program a terminado\n”);
返回3;
}
addr\u len=sizeof(服务器地址);
conectado=connect(客户端,(结构sockaddr*)和服务器地址,大小(服务器地址));
如果(conectado==-1)
{
perror(“连接”);
返回4;
}
printf(“服务器地址:%s y服务器端口%hu\n”),inet\u ntoa(服务器地址sin\u地址),
ntohs(服务器地址单端口);
做{
printf(“传送完整文件入口:\n”);
scanf(“%s”,名称);/*Consigo nombre del archivo a transmitir*/
fp=fopen(名称为“r”);
如果(fp==NULL){
佩罗(“错误”);
返回0;
}
fseek(fp,0,SEEK_END);
tamano_archivo=ftell(fp);/*tamano del archivo a transmitir*/
倒带(fp);
paquetes_archivo=ceil(tamano_archivo/1460)+1;/*环境的变化*/
printf(“%lu,%lu\n”,tamano_archivo,paquetes_archivo);
/*传输环境信息*/
info_tx.tamanio=tamano_archivo;
info_tx.paquetes=paquetes_archivo;
strcpy(信息发送名称、名称);
bytesaenviar=sizeof(信息发送);
bytestx=发送(客户端和信息发送,bytesaenviar,0);
/*埃斯佩罗recibido确认书*/
bytesrecibidos=recv(客户机和信息接收),sizeof(信息接收),0;
flag=比较者(信息接收、信息发送);/*比较者*/
如果(flag==true){/*si*/
如果(paquetes_archivo>1){/*envio archivo*/

对于(i=1;i>>paso#6让我们先讨论TCP套接字

当谈到TCP套接字时,它是一个数据流。 TCP将数据视为非结构化的、但有序的字节流,这与socket.io的类型不同

TCP会不时从发送缓冲区抓取数据块并将数据传递到网络层。可抓取和放置在段中的最大数据量受最大段大小(MSS)的限制。MSS通常通过首先确定最大链路层帧的长度来设置

所以这取决于设备

例如,您有两条消息,每条消息都有1000字节的数据,您可以调用:

--------------客户端----------------

socket.onReceived(data => {
    // process(data)
})
--------------服务器端-----------------

socket.onReceived(data => {
    // process(data)
})
使用上述伪代码,您应该注意:

在onReceived块上接收和调用的数据可能不是FirstMessage的1000字节

  • 它可能是第一个400字节,然后在另一个事件中,您会收到400字节,然后是更多的400字节
    socket.onReceived(data => {
        // process(data)
    })
    
    // use Int32, 4 bytes to indicate the length of message after it
    
    -------------- client side ----------------
        client.send(theFirstMessage.length)    // Int32
        client.send(theFirstMessage) // 1000 bytes
    
        client.send(theSecondMessage.length) 
        client.send(theSecondMessage) // 1000 bytes
    
    
    -------------- server side -----------------
    
        var buffer = Buffer()
    
        socket.onReceived(data => {
            buffer.append(data)
            
            let length = Int32(buffer[0...3])
            
            if (buffer.length >= length + 4) {
               let theRequest = buffer[4 ... 4 + length - 1]
               process(theRequest)
    
               buffer = buffer.dropFirst(4 + length)
            }
           
        })