C 通过套接字发送巨大数组
我试图通过C中的TCP套接字从服务器向客户端发送一个100.000.000字节(可能更多)的字符数组 我是这样做的:C 通过套接字发送巨大数组,c,sockets,C,Sockets,我试图通过C中的TCP套接字从服务器向客户端发送一个100.000.000字节(可能更多)的字符数组 我是这样做的: char *array; // global array malloc'd (SIZE) //####################### // server code //####################### int i; int SIZE = 100000000 for (i = 0; i < SIZE; i = i + 4){ wr
char *array; // global array malloc'd (SIZE)
//#######################
// server code
//#######################
int i;
int SIZE = 100000000
for (i = 0; i < SIZE; i = i + 4){
write(id, &array[i], 4); // write 4 bytes every time
}
//#######################
// client code
//#######################
int i;
int SIZE = 100.000.000
for (i = 0; i < SIZE; i = i + 4)
read(id, array + i, 4); // read 4 bytes
char*数组;//全局数组malloc'd(大小)
//#######################
//服务器代码
//#######################
int i;
整数大小=100000000
对于(i=0;i
问题:
1) 当我尝试发送更多字节时,传输出现问题。例如,如果我将4改为100,它会显示“断管”。为什么会这样
2) 我知道这不是一种“安全”的读/写方式,因为我没有检查read()和write()返回值。我该怎么做
3) 我必须使用htonl()和ntohl()函数吗
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include <sys/types.h>
#include <sys/socket.h>
//in @param
//@param fd the socket file descriptor
//@param array an array of data source to write to send to the connected client
//@param SIZE the size of data source to send to the client
//@param sz_emit the size of data to send in one loop step
//out @param
//total length of data emited to the client
int write_to_client(int fd, char* array, int SIZE, int sz_emit)
{
//#######################
// server code
//#######################
int i=0, sz=0;
for(i = 0; i < SIZE; i += sz_emit )
{
while(sz_emit-sz)
{
sz+=write(id, array+i+sz, sz_emit-sz);
}
sz = 0;
}
return i;
}
//#######################
// client code
//#######################
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//in @param
//@param fd is the file descriptor of the socket to read from
//@param SIZE the size of datas you want to read from the socket
//@param sz_received the size of byte to read in one loop step
//@param length, the length of data received
//@param read_err if 0 no error if -1 an error occurs use errno from #include <errno.h> to know more about that error
//out @param
//a pointer to an array of size SIZE containing the data readed
char* receive_from_server(int fd, int SIZE, int sz_received, int* length, int* read_err)
{
*read_err = 0;
int i = 0, sz = 0, rt = 0, count=0;
char *array = (char *)malloc(SIZE);
memset(array, 0, SIZE);
for (i = 0; i < SIZE; i += sz_received)
{
while(sz_received-sz)
{
rt = read(id, array + i + sz, sz_received-sz);
if(rt==-1)
{
*read_err=rt;
printf("an error occurs\n");
goto l;
}
if(!rt)goto l;
sz+=rt;
count += sz;
}
sz = 0;
}
l: *length = count;
return array;
}
一些注意事项:
当您想要传输多字节实体(例如短、int、long、utf-16等)时,需要注意endianess,但如果您的数据是utf-8或ascii文本,则不需要它
一些注意事项:
当你想传输一个多字节实体时,比如短、int、long、utf-16等,你需要注意尾数,但如果你的数据是utf-8或ascii文本,你就不需要它。我认为Narcisse Doudieu Siewe
的答案有一些错误。我想当大小不是sz_emit的多重数时,它会失败。
例如,我们以8字节块的形式发送了20个字节,而最后一个数据块(或数据包)的长度为4字节。如果我们尝试发送最后8个字节的块,只剩下4个字节,而while循环将是无限的,就像while(8-4),它永远不会到达sz=8,因为下一次发送只会增加0。所以我写了这样的修改(未测试,我将很快进行测试,并编写第二种方法,考虑到这个边界条件)
/**
*@param sock_fd-要向其写入(发送)数据的套接字的文件描述符
*@param packetLength-要在一个数据包中发送的数据大小
*@param data-要发送的二进制数据(无符号字符数组)
*@param dataLength-要发送的所有二进制数据的大小
*@return-状态码成功或失败
*/
结果发送二进制文件(常量sock\u fd\u t sock\u fd、常量大小\u t packetLength、常量无符号字符*数据、常量大小\u t数据长度){
ssize_t leftPacketLength=0;
ssize_t offset=0;
ssize_t sentPacketLength=0;
//发送循环中的每个数据包
对于(int-leftDataLength=dataLength;leftDataLength>0;leftDataLength-=packetLength){
leftPacketLength=(leftDataLength>packetLength)?packetLength:leftDataLength;
而(leftPacketLength>0){
sentPacketLength=发送(sock_fd,数据+偏移量,leftPacketLength,0);
如果(sentPacketLength<0){
fprintf(stderr,“%s:向套接字发送数据时出错。\n”,\uuu func\uuu);
佩罗尔(埃尔诺);
返回失败;
}
偏移量+=sentPacketLength;
leftPacketLength-=sentPacketLength;
}
}
如果(偏移量!=数据长度)
返回失败;
回归成功;
}
/**
*@param sock_fd-从中读取(接收)数据的套接字的文件描述符
*@param packetLength—一个数据包中要接收的数据的大小
*@param data-已接收二进制数据(无符号字符数组)-以前已分配
*@param dataLength-接收到的所有二进制数据的大小-以前定义
*@return-状态码成功或失败
*/
结果记录二进制文件(常量sock\u fd\u t sock\u fd、常量大小\u t packetLength、无符号字符*数据、常量大小\u t数据长度){
ssize_t leftPacketLength=0;
ssize_t offset=0;
ssize_t recvedPacketLength=0;
对于(int-leftDataLength=dataLength;leftDataLength>0;leftDataLength-=packetLength){
leftPacketLength=(leftDataLength>packetLength)?packetLength:leftDataLength;
而(leftPacketLength>0){
recvedPacketLength=recv(sock_fd,数据+偏移量,leftPacketLength,0);
如果(recvedPacketLength<0){
fprintf(stderr,“%s:从套接字接收数据时出错。\n”,\uuu func\uuu);
佩罗尔(埃尔诺);
返回失败;
}
偏移量+=回收的包装长度;
leftPacketLength-=recvedPacketLength;
}
}
如果(偏移量!=数据长度)
返回失败;
回归成功;
}
在传输实际二进制数据之前,还需要通过套接字发送二进制数据send/recv的大小。它需要知道我们需要读取多少字节 我认为Narcisse Doudieu Siewe的回答有一些错误。我想当大小不是sz_emit的多重数时,它会失败。
例如,我们以8字节块的形式发送了20个字节,而最后一个数据块(或数据包)的长度为4字节。如果我们尝试发送最后8个字节的块,只剩下4个字节,而while循环将是无限的,就像while(8-4),它永远不会到达sz=8,因为下一次发送只会增加0。所以我写了这样的修改(未测试,我将很快进行测试,并编写第二种方法,考虑到这个边界条件)
/**
*@param sock_fd-要向其写入(发送)数据的套接字的文件描述符
*@param packetLength-要在一个数据包中发送的数据大小
*@param data-要发送的二进制数据(无符号字符数组)
*@param dataLength-要发送的所有二进制数据的大小
*@return-状态码成功或失败
*/
结果发送二进制文件(常量sock\u fd\u t sock\u fd、常量大小\u t packetLength、常量无符号字符*数据、常量大小\u t数据长度){
ssize_t leftPacketLength=0;
ssize_t offset=0;
ssize_t sentPacketLength=0;
//发送循环中的每个数据包
法罗群岛
//server side
int SIZE = 100000000;
char array_to_send[SIZE]={'r'};
int sz_data_emited = write_to_client(sock, array_to_send, SIZE, 4);
printf("how many byte data emited:%d\n", sz_data_emited);
//client side
int SIZE = 100000000, length = 0, read_err=0;
char*array_received = NULL;
array_received = receive_from_server(sock, SIZE, 4, &length, &read_err);
if(!read_err)printf("get some datas\n");
// free array_received when finished...free(array_received)
/**
* @param sock_fd - the file descriptor of the socket to write (send) data to
* @param packetLength - the size of data to send in one packet
* @param data - binary data to send (unsigned char array)
* @param dataLength - the size of all binary data to send
* @return - status code SUCCESS or FAILURE
*/
result_t send_binary(const sock_fd_t sock_fd, const size_t packetLength, const unsigned char *data, const size_t dataLength) {
ssize_t leftPacketLength = 0;
ssize_t offset = 0;
ssize_t sentPacketLength = 0;
// send each packet of data in the loop
for(int leftDataLength=dataLength; leftDataLength>0; leftDataLength -= packetLength) {
leftPacketLength = (leftDataLength > packetLength) ? packetLength : leftDataLength;
while(leftPacketLength > 0) {
sentPacketLength = send(sock_fd, data + offset, leftPacketLength, 0);
if(sentPacketLength < 0) {
fprintf(stderr, "%s: Error while sending data to the socket.\n", __func__);
perror(errno);
return FAILURE;
}
offset += sentPacketLength;
leftPacketLength -= sentPacketLength;
}
}
if(offset != dataLength)
return FAILURE;
return SUCCESS;
}
/**
* @param sock_fd - the file descriptor of the socket to read (recieve) data from
* @param packetLength - the size of data to recieve in one packet
* @param data - binary data received (unsigned char array) - previously allocated
* @param dataLength - the size of all binary data received - previously defined
* @return - status code SUCCESS or FAILURE
*/
result_t recv_binary(const sock_fd_t sock_fd, const size_t packetLength, unsigned char *data, const size_t dataLength) {
ssize_t leftPacketLength = 0;
ssize_t offset = 0;
ssize_t recvedPacketLength = 0;
for(int leftDataLength=dataLength; leftDataLength > 0; leftDataLength -= packetLength) {
leftPacketLength = (leftDataLength > packetLength) ? packetLength : leftDataLength;
while(leftPacketLength > 0) {
recvedPacketLength = recv(sock_fd, data + offset, leftPacketLength, 0);
if(recvedPacketLength < 0) {
fprintf(stderr, "%s: Error while receiving data from the socket.\n", __func__);
perror(errno);
return FAILURE;
}
offset += recvedPacketLength;
leftPacketLength -= recvedPacketLength;
}
}
if(offset != dataLength)
return FAILURE;
return SUCCESS;
}