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