2009-03-23 5 views
1

이전 질문 (Why do I get weird results when reading an array of integers from a TCP socket?)에 이어 다음 코드를 제안했습니다. 작동하는 것처럼 보입니다. 코드 샘플은 적은 수의 배열 요소에서 잘 작동하지만 일단 커지면 데이터가 끝까지 손상됩니다.TCP를 통한 int 배열을 보낼 때 첫 번째 값만 정확합니다.

이 TCP를 통해 INT의 배열을 보낼 수있는 코드 :

#define ARRAY_LEN 262144 

long *sourceArrayPointer = getSourceArray(); 

long sourceArray[ARRAY_LEN]; 
for (int i = 0; i < ARRAY_LEN; i++) 
{ 
    sourceArray[i] = sourceArrayPointer[i]; 
} 

int result = send(clientSocketFD, sourceArray, sizeof(long) * ARRAY_LEN); 

그리고 이것은 INT의 배열을받을 수있는 코드 :

#define ARRAY_LEN 262144 

long targetArray[ARRAY_LEN]; 
int result = read(socketFD, targetArray, sizeof(long) * ARRAY_LEN); 

처음 몇 번호가 잘됩니다, 배열을 더 내려 가면 숫자가 완전히 달라지기 시작합니다. 결국 숫자가 다음과 같이 표시되어야합니다.

0 
0 
0 
0 
0 
0 
0 
0 
0 
0 

하지만 실제로 이렇게 나옵니 까?

4310701 
0 
-12288 
32767 
-1 
-1 
10 
0 
-12288 
32767 

잘못된 보내기/받기 크기를 사용하고 계신 이유는 무엇입니까?

+0

덧붙여 말하자면 송신하기 전에 배열 내용을 로컬 배열 변수에 복사 할 필요가 없습니다. 이것은 메모리와 CPU주기를 낭비하는 것입니다. –

+0

배열에 복사하는 대신 포인터를 사용하려고하면 -1이 반환됩니다. 이것이 복사 방법을 사용하는 이유입니다. –

답변

7

read(..., len)을 호출해도 소켓에서 len 바이트가 읽히지 않으면 최대 값은 len 바이트입니다. 배열이 다소 커서 많은 TCP/IP 패킷으로 분할되므로 read 호출은 배열의 일부만 반환하는 반면 나머지는 여전히 "전송 중"입니다. read()은 수신 한 바이트 수를 반환하므로 원하는 모든 것을 수신 할 때까지 다시 호출해야합니다.다음과 같이 할 수 있습니다.

long targetArray[ARRAY_LEN]; 

char *buffer = (char*)targetArray; 
size_t remaining = sizeof(long) * ARRAY_LEN; 
while (remaining) { 
    ssize_t recvd = read(socketFD, buffer, remaining); 
    // TODO: check for read errors etc here... 
    remaining -= recvd; 
    buffer += recvd; 
} 
+0

가장 논리적 인 대답처럼 들립니다. 나는 이것을 지금 시험 할 것이다. –

+0

흠, read (...)의 결과는 읽은 유효한 int 요소의 실제 개수와 전혀 상관 관계가없는 것처럼 보입니다. 그것은 또한 읽을 때마다 바뀌는 것 같습니다 (즉, 때로는 ~ 65593 및 기타 ~ 49923). 그럼에도 불구하고 이전에 해본대로 책을 읽을 것입니다. –

+0

이 줄은 컴파일하지 않는 것 같습니다 : buffer + = recvd; 나는 오류를 얻는다 : 타입 'void *'의 포인터는 산술에 사용된다. –

5

다음과 같습니까?

for (int i = 0; sourceArrayPointer < i; i++) 

당신은 사과와 오렌지 (읽기 포인터와 정수)를 비교하고 있습니다. long 배열의 포인터가> 0 (대부분 항상)이므로이 루프는 실행되지 않습니다. 따라서 수신 측에서는 단위 변환 된 배열을 읽으므로 잘못된 숫자가 전달됩니다. <net/hton.h>

http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking

+0

오타가 있었어야합니다. 첫 번째 줄은 어떻게 컴파일됩니까? (또는 내 C가 녹슬 었음) – erikkallen

+0

@erikkallen : 그래서 첫 번째 줄에 질문이 있습니다. – dirkgently

+0

우리가 익숙한 인텔 아키텍처에서 "int"와 "long *"(long에 대한 포인터)는 모두 32 비트 값입니다. "int"는 32 비트이고 "long에 대한 포인터"는 32 비트 폭의 메모리 주소입니다. 컴파일러는 당신이 비교를 할 수있게 해줄 것입니다. (아마도 경고를 던집니다) – poundifdef

1

사용 기능,하지만 당신은 당신이 원하는 경우 플랫폼의 endianness 돌봐해야합니다

그것은 오히려 것 다른 플랫폼에서 TCP를 사용합니다.

curl이나 ACE와 같은 네트워킹 라이브러리를 사용하는 것이 훨씬 간단합니다 (디자인 패턴과 같이 더 높은 수준에서 더 많은 것을 배울 수 있습니다).

+0

나는 dirkgently의 대답은 OP가보고있는 문제이지만, 당신의 요점은 유효하며 해결되어야한다고 생각합니다. +1 – rmeador

0

이 질문에 관련되지에서

for (int i = 0; i < ARRAY_LEN; i++) 
0

TCP가 스트림에 보내는 데이터를 어떻게 패킷으로 처리 할 것인지는 보장 할 수 없으며 응용 프로그램 수준에서 올바른 순서로 끝나도록 보장합니다. 따라서 결과 값을 확인하고 올바른 바이트 수를 읽을 때까지 계속 읽어야합니다. 그렇지 않으면 전체 데이터를 읽지 못할 것입니다. 바이트 배열보다는 긴 배열을 사용하는 것이 더 어렵습니다. 데이터는 긴 경계에 정렬되지 않을 수도있는 여러 개의 청크로 전송 될 수 있습니다.

0

많은 문제가 있습니다. 첫째, 이것이 내가 이해할 수 있도록 보내는 코드를 다시 작성하는 방법입니다. getSourceArray는 항상 크기가 ARRAY_LEN 인 정적 또는 malloced 버퍼에 유효한 포인터를 리턴한다고 가정합니다. 나중에 코드에서 sourceArrayPointer가 필요 없다고 가정합니다.

#define ARRAY_LEN 262144 

long *sourceArrayPointer = getSourceArray(); 

long sourceArray[ARRAY_LEN]; 
long *sourceArrayIdx = sourceArray; 

for (; sourceArrayIdx < sourceArray+ARRAY_LEN ;) 
    sourceArrayIdx++ = sourceArrayPointer++; 

int result = send(clientSocketFD, sourceArray, sizeof(long) * ARRAY_LEN); 
if (result < sizeof(long) * ARRAY_LEN) 
    printf("send returned %d\n", result); 

원래의 코드를 보면 나는 당신이 루프 엉망이되었다는 것을 추측 결코 당신의 메모리 sourceArray 점에 될 일이 임의대로 스팸 전송의 결과로 실행하지거야. 기본적으로 귀하의 상태

sourceArrayPointer < i; 

은 처음부터 완전히 실패하지 않을 것입니다.

+0

다시 말하지만 마지막 포인트에 관해서는 오타였습니다.이 버그는 원래 코드에는 존재하지 않습니다. 어쨌든 고마워. –

관련 문제