문제

클라이언트에서 전체 구조체를 보낸 다음 서버에 구조체 멤버 "ID"를 출력하려는 ​​클라이언트 및 서버 프로그램이 있습니다.

나는 모든 연결 등을 완료했으며 이미 다음을 통해 문자열을 보냈습니다.

send(socket, string, string_size, 0);

그렇다면 send()를 통해 문자열 대신 구조체를 보내는 것이 가능할까요?서버의 버퍼를 동일한 유형의 빈 구조체로 교체하고 갈 수 있나요?

도움이 되었습니까?

해결책

음...제대로 수행하고 있다면 네트워크를 통해 구조체를 보내는 것은 다소 어렵습니다.

Carl의 말이 맞습니다. 다음과 같이 말하면 네트워크를 통해 구조체를 보낼 수 있습니다.

send(socket, (char*)my_struct, sizeof(my_struct), 0);

하지만 문제는 다음과 같습니다.

  • sizeof(my_struct)는 클라이언트와 서버 간에 변경될 수 있습니다.컴파일러는 종종 어느 정도의 패딩과 정렬을 수행하므로 정렬을 명시적으로 정의하지 않는 한(#pragma pack()을 사용하여) 해당 크기가 다를 수 있습니다.
  • 다른 문제는 바이트 순서인 경향이 있습니다.일부 머신은 빅엔디안이고 다른 머신은 리틀엔디안이므로 바이트 배열이 다를 수 있습니다.실제로 서버나 클라이언트가 Intel이 아닌 하드웨어에서 실행되고 있지 않는 한(아마도 그렇지 않을 수도 있음) 이 문제는 실제보다 이론적으로 더 많이 존재합니다.

그래서 사람들이 자주 제안하는 해결책은 구조체를 직렬화하는 루틴을 갖는 것입니다.즉, 한 번에 하나의 데이터 멤버를 구조체에 전송하여 클라이언트와 서버가 프로그램에 코딩한 정확한 지정된 바이트 수만 send() 및 recv()하도록 보장합니다.

다른 팁

클라이언트와 서버 시스템이 "동일"합니까?당신이 제안하는 것은 각 끝의 C 컴파일러가 메모리의 구조를 정확히 동일하게 배치하는 경우에만 작동합니다.이것이 사실이 아닌 데에는 많은 이유가 있습니다.예를 들어 클라이언트와 서버 시스템의 아키텍처가 다를 수 있으며 메모리에서 숫자를 나타내는 방식(빅 엔디안, 리틀 엔디안)이 다를 수 있습니다.클라이언트 시스템과 서버 시스템의 아키텍처가 동일하더라도 두 개의 서로 다른 C 컴파일러는 메모리에 구조체를 배치하는 방법에 대해 서로 다른 정책을 가질 수 있습니다(예:단어 경계의 정수를 정렬하기 위해 필드 사이에 패딩을 추가합니다.심지어 같은 다른 플래그를 사용하는 컴파일러는 다른 결과를 제공할 수 있습니다.

실질적으로 나는 귀하의 클라이언트와 서버가 동일한 종류의 기계이므로 귀하가 제안하는 것이 작동할 것이라고 추측합니다. 그러나 일반적으로 그렇지 않다는 점을 인식해야 하며 이것이 바로 CORBA와 같은 표준이 발명된 이유입니다. , 또는 사람들이 XML과 같은 일반적인 표현을 사용하는 이유.

클라이언트와 서버가 구조체를 정확히 동일한 방식으로 배치했다면, 즉 필드의 크기가 모두 동일하고 패딩이 동일하다는 의미입니다.예를 들어 long 구조체에서는 한 컴퓨터에서는 32비트이고 다른 컴퓨터에서는 64비트일 수 있으며, 이 경우 구조체가 올바르게 수신되지 않습니다.

귀하의 경우 클라이언트와 서버가 항상 매우 유사한 C 구현을 사용하는 경우(예를 들어 이것이 기본 개념을 배우기 위해 사용하는 코드일 뿐이거나 다른 이유로 인해 코드가 현재 버전의 OSX에서 실행해야 하는 경우), 그러면 아마도 벗어날 수 있습니다.여러분의 코드가 다른 플랫폼에서 반드시 제대로 작동하는 것은 아니며 대부분의 실제 상황에서 사용하기에 적합하려면 더 많은 작업이 필요하다는 점을 기억하세요.

대부분의 클라이언트-서버 애플리케이션의 경우 이는 일반적으로 이를 수행할 수 없다는 것을 의미합니다.실제로 수행하는 작업은 전송된 바이트 수, 순서, 의미 등을 기준으로 메시지를 정의하는 것입니다.그런 다음 각 끝에서 사용 중인 구조체가 정확히 필요한 레이아웃을 가지고 있는지 확인하기 위해 플랫폼별 작업을 수행합니다.그럼에도 불구하고 구조체 little-endian의 정수 멤버를 전송하고 코드를 big-endian 시스템에서 실행하려면 바이트 교환을 수행해야 할 수도 있습니다.XML, json 및 Google의 프로토콜 버퍼와 같은 데이터 교환 형식이 존재하므로 이러한 성가신 작업을 수행할 필요가 없습니다.

[편집하다:물론 일부 구조체 멤버는 유선으로 전송될 수 없다는 점을 기억하세요.예를 들어 구조체에 포인터가 있는 경우 주소는 송신 시스템의 메모리를 참조하며 수신 측에서는 쓸모가 없습니다.이것이 이미 당신에게 분명하다면 사과드립니다. 그러나 C로 막 시작하는 모든 사람에게는 분명하지 않습니다.]

가능합니다. 하지만 2가지 중요한 사항을 알고 있어야 합니다.

  1. 양쪽 끝에 있는 프로그램은 다음과 같아야 합니다. ABI 호환 가능.일반적으로 양쪽 끝이 동일한 프로세서 아키텍처, 동일한 OS에서 실행되고 동일한 컴파일러 및 컴파일러 플래그로 컴파일된 경우입니다.
  2. TCP는 스트림입니다.전체 구조체를 보내고 있는지 확인해야 합니다.send() 호출에 대한 문서를 살펴보십시오. 보낸 바이트 수를 반환합니다. 이는 사용자가 지시한 것보다 작을 수 있습니다.수신자 측에서도 마찬가지입니다.1번의 보내기 호출로 구조체를 보냈다고 해서 1번의 수신 호출로 구조체를 수신한다는 의미는 아닙니다.모든 조각을 얻으려면 여러 번의 수신 호출이 필요합니다.

예, 동일한 유형의 구조체는 모두 동일한 크기입니다.포인터 캐스팅이 올바르게 되었다면 잘 진행된 것입니다.

일반적으로 클라이언트와 서버가 메모리에 같은 방식으로 구조를 배치하더라도 이렇게 하는 것은 좋지 않은 생각입니다.

더 복잡한 데이터 구조(포인터 포함)를 앞뒤로 전달할 의도가 없더라도 네트워크를 통해 데이터를 보내기 전에 데이터를 직렬화하는 것이 좋습니다.

데이터를 텍스트 파일로 보낸 후 수신 후 디코딩합니다.데이터를 전송하려는 경우 이것이 가장 좋은 방법입니다!!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top