C의 소켓을 통한 구조 전달
클라이언트에서 서버로 전체 구조를 전달하거나 반대로 전달하려고 합니다.나의 구조를 다음과 같이 가정하자.
struct temp {
int a;
char b;
}
sendto를 사용하여 구조변수 주소를 전송하고 recvfrom 기능을 사용하여 반대편에서 수신하고 있습니다.그러나 나는 수신측에서 원본 데이터를 받을 수 없다.sendto 함수에서는 수신한 데이터를 type structure temp 변수에 저장합니다.
n = sendto(sock, &pkt, sizeof(struct temp), 0, &server, length);
n = recvfrom(sock, &pkt, sizeof(struct temp), 0, (struct sockaddr *)&from,&fromlen);
여기서 pkt는 구조 temp 유형의 변수입니다.
8바이트의 데이터를 받고 있는데 인쇄하려고 하면 단순히 가비지 값이 표시됩니다.고쳐줄 사람 없어?
주의: 서드파티 라이브러리를 사용할 필요가 없습니다.
편집 1:저는 이 연재 개념은 정말 처음입니다.하지만 직렬화를 하지 않고 소켓을 통해 구조를 보낼 수 있습니까?
편집 2:sendto 및 recvfrom 함수를 사용하여 문자열이나 정수 변수를 전송하려고 하면 수신측에서 데이터가 올바르게 수신됩니다.구조물의 경우에는 왜 안 되는가?만약 serialize 기능을 사용할 필요가 없다면 구조의 모든 구성원을 개별적으로 보내야 하나요?n개의 멤버 수가 있는 경우 데이터를 송수신하기 위해서만 n개의 코드 행이 추가되기 때문에 이것은 정말 적절한 솔루션이 아닙니다.
이것은 매우 나쁜 생각이다.이진 데이터는 항상 다음과 같은 방법으로 전송해야 합니다.
전체 구조를 파일이나 소켓에 쓰는 것이 아니라 바이너리 방식으로 쓰지 마십시오.
항상 각 필드를 구분하여 같은 방법으로 읽으십시오.
다음과 같은 기능이 필요합니다.
unsigned char * serialize_int(unsigned char *buffer, int value)
{
/* Write big-endian int value into buffer; assumes 32-bit int and 8-bit char. */
buffer[0] = value >> 24;
buffer[1] = value >> 16;
buffer[2] = value >> 8;
buffer[3] = value;
return buffer + 4;
}
unsigned char * serialize_char(unsigned char *buffer, char value)
{
buffer[0] = value;
return buffer + 1;
}
unsigned char * serialize_temp(unsigned char *buffer, struct temp *value)
{
buffer = serialize_int(buffer, value->a);
buffer = serialize_char(buffer, value->b);
return buffer;
}
unsigned char * deserialize_int(unsigned char *buffer, int *value);
또는 버퍼 관리 등과 관련하여 이를 설정하는 방법은 물론 여러 가지가 있습니다.그런 다음 전체 구조를 직렬화/비직렬화하는 상위 수준의 함수를 수행해야 합니다.
이것은, 버퍼간에 시리얼화가 행해지는 것을 전제로 하고 있습니다.즉, 시리얼화는 최종 수신처가 파일인지 소켓인지를 알 필요가 없습니다.또한 메모리 오버헤드를 지불하지만 일반적으로 성능상의 이유로 좋은 설계입니다(소켓에 각 값을 쓰기()는 하고 싶지 않습니다).
위의 내용을 이해하면 구조 인스턴스를 시리얼화하고 전송할 수 있습니다.
int send_temp(int socket, const struct sockaddr *dest, socklen_t dlen,
const struct temp *temp)
{
unsigned char buffer[32], *ptr;
ptr = serialize_temp(buffer, temp);
return sendto(socket, buffer, ptr - buffer, 0, dest, dlen) == ptr - buffer;
}
상기 사항에 대해 주의해 주십시오.
- 송신할 구조가 최초로 필드별로 시리얼화됩니다.
buffer
. - 시리얼라이제이션 루틴은 버퍼 내의 다음 빈 바이트로 포인터를 반환합니다.이것을 사용하여 시리얼라이제이션된 바이트 수를 계산합니다.
- 이 예의 시리얼라이제이션 루틴은 버퍼 오버플로로부터 보호되지 않습니다.
- 이 경우 반환값은 1입니다.
sendto()
콜이 성공했습니다.그렇지 않으면 0이 됩니다.
pragma' 팩 옵션을 사용하면 문제가 해결되었지만 종속성이 있는지 잘 모르겠습니다.
#pragma pack(1) // this helps to pack the struct to 5-bytes
struct packet {
int i;
char j;
};
#pragma pack(0) // turn packing off
그리고 다음 코드 라인은 문제없이 잘 작동했습니다.
n = sendto(sock,&pkt,sizeof(struct packet),0,&server,length);
n = recvfrom(sock, &pkt, sizeof(struct packet), 0, (struct sockaddr *)&from, &fromlen);
전용 시리얼라이제이션 루틴을 작성할 필요가 없습니다.short
그리고.long
정수형 - 사용htons()
/htonl()
POSIX 기능
시리얼화 코드를 직접 작성하지 않을 경우 적절한 시리얼화 프레임워크를 찾아 사용합니다.
구글의 프로토콜 버퍼가 가능할까?
시리얼화는 좋은 생각입니다.또한 Wireshark를 사용하여 트래픽을 모니터링하고 패킷에서 실제로 전달되는 내용을 파악할 수도 있습니다.
서드파티 라이브러리에 의존하는 대신 태그, 길이 및 값을 사용하여 기본 프로토콜을 쉽게 만들 수 있습니다.
Tag: 32 bit value identifying the field
Length: 32 bit value specifying the length in bytes of the field
Value: the field
필요에 따라 연결합니다.태그에는 enum을 사용합니다.네트워크 바이트 순서를 사용합니다.
부호화, 복호화도 간단.
또, TCP 를 사용하고 있는 경우는, 데이터 스트림이기 때문에, 예를 들면 3 개의 패킷을 송신해도, 3 개의 패킷을 수신할 필요는 없습니다.노드레이/나겔 알고리즘에 따라 스트림에 "머지"되어 모든 것을 1회 수신할 수 있습니다.예를 들어 RFC1006을 사용하여 데이터를 구분해야 합니다.
UDP는 더 쉽고, 전송되는 각 패킷에 대해 고유한 패킷을 수신할 수 있지만, 보안은 훨씬 떨어집니다.
전송하는 데이터의 형식이 매우 간단한 경우 ANSI 문자열로 변환하거나 ANSI 문자열에서 변환하는 것은 간단하고 휴대할 수 있습니다.
언급URL : https://stackoverflow.com/questions/1577161/passing-a-structure-through-sockets-in-c
'programing' 카테고리의 다른 글
vuejs2 데이터에 하위 구성 요소 동적 삽입($compile 또는 v-html 남용 없음) (0) | 2022.07.10 |
---|---|
Unsupported Operation이 표시되는 이유목록에서 요소를 제거하려고 할 때 예외가 발생합니까? (0) | 2022.07.10 |
Vue에 클래스가 존재하는지 여러 요소를 검사하려면 어떻게 해야 합니까? (0) | 2022.07.10 |
Vue 경고 수정 방법:구성요소 렌더링 함수에 무한 업데이트 루프가 있을 수 있습니다. (0) | 2022.07.10 |
Vue.jsVue.jsv-timeout 태그 인 (0) | 2022.07.10 |