2017-07-23 1 views
0

Ich verwende IPC (Interprozesskommunikation), um Daten zwischen zwei C++ - Programmen zu senden. Für den IPC verwende ich den grundlegenden TCP/IP Winsock2-Code.IPC Erste send() - und recv() - Aufrufe in C++ TCP dauert länger

Grundsätzlich ist die Idee, dass ich 3D-Datenrahmen zwischen den beiden Anwendungen senden, verarbeitet man die Daten mit GPU/CUDA und die andere zeigt es mit einem 3de Party-Bibliothek (PCL). Meine Anwendungen sind sehr reich an Daten (zB 30fps, 4Mb pro Frame), aber das sollte für IPC kein Problem sein, soweit ich weiß.

So wie jeder Rahmen Verarbeitung auf der GPU abgeschlossen ist, konvertiere ich die Frames Daten (X, Y, Z-Coords des Typs Float; R, G, B vom Typ Uint8_t jeweils) in Bytes und senden sie nacheinander .

Dabei habe ich etwas merkwürdiges bemerkt. In meinem Code habe ich 9 send() Befehle hintereinander.

  • 1ste: Senden eines einzelnen Zeichens, das als Name des Frames fungiert.
  • 2de: Ein einzelnes int mit der Anzahl der eingehenden 3D-Punkte.
  • 3-5th: RGB-Werte
  • 6-8th: XYZ-Werte
  • 9.: Ende der Comms überprüfen Sie die Viewer-Anwendung zu schließen.

Dieser ganze Prozess dauert ca. 30ms. Was ich seltsam fand, war, wohin die meiste Zeit ging. Nach jedem Ereignis Timing habe ich folgendes:

  • 1ste: 20 ms (1 Byte-Daten)
  • 2DE: < 1ms (4 Byte Daten)
  • 3-5: 2 ms (921600 Bytes von Daten)
  • 6-8: 3 ms (3.686.400 Bytes von Daten)
  • 9th: 1 ms (1 Byte-Daten)

Warum ist es, dass für den ersten Sendebefehl er eine so lange Zeit in Anspruch nimmt, selbst zu vollenden, wenn es ist nur 1 Byte Daten und dann der Rest der Daten in Rekordzeit abgeschlossen. Zwischen jeder Ausführung dieser Schleife liegt eine Zeitverzögerung von ca. 20 ms, die darauf wartet, dass der GPU-Code beendet wird. Geht die TCP-Verbindung in einen Schlafzustand, und wenn ja, kann ich sie irgendwie deaktivieren.

TCP-Socket-Code:

SOCKET Create_Server_Socket(PCSTR IP, PCSTR port) 
{ 
struct addrinfo *result = NULL, *ptr = NULL, hints; 
int iResult; 

ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP; 
hints.ai_flags = AI_PASSIVE; 

// Resolve the local address and port to be used by the server 
iResult = getaddrinfo(NULL, port, &hints, &result); 
if (iResult != 0) { 
    printf("getaddrinfo failed: %d\n", iResult); 
    WSACleanup(); 
    return 1; 
} 

SOCKET ListenSocket = INVALID_SOCKET; 

ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 

if (ListenSocket == INVALID_SOCKET) { 
    printf("Error at socket(): %ld\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    WSACleanup(); 
    return 1; 
} 

iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); 
if (iResult == SOCKET_ERROR) { 
    printf("bind failed with error: %d\n", WSAGetLastError()); 
    freeaddrinfo(result); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

freeaddrinfo(result); 

if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) { 
    printf("Listen failed with error: %ld\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

SOCKET ClientSocket; 

ClientSocket = INVALID_SOCKET; 

// Accept a client socket 
ClientSocket = accept(ListenSocket, NULL, NULL); 
if (ClientSocket == INVALID_SOCKET) { 
    printf("accept failed: %d\n", WSAGetLastError()); 
    closesocket(ListenSocket); 
    WSACleanup(); 
    return 1; 
} 

return (ClientSocket); 

}

-Code in Frage:

iResult = send(ConnectSocket, (char*)&name, sizeof(char), 0); //Takes >20ms to complete 
iResult = send(ConnectSocket, (char*)&points, 4, 0); 
iResult = send(ConnectSocket, (char*)Red_t, sizeof(uint8_t) * depth_width *depth_height, 0); 
iResult = send(ConnectSocket, (char*)Green_t, sizeof(uint8_t) * depth_width *depth_height, 0); 
iResult = send(ConnectSocket, (char*)Blue_t, sizeof(uint8_t) * depth_width *depth_height, 0); 
iResult = send(ConnectSocket, (char*)z_t, sizeof(uint16_t) * depth_width *depth_height, 0); 
iResult = send(ConnectSocket, (char*)x_t, sizeof(float) * depth_width *depth_height, 0) 
iResult = send(ConnectSocket, (char*)y_t, sizeof(float) * depth_width *depth_height, 0); 
iResult = send(ConnectSocket, "a", sizeof(char), 0); 

ich auf Windows arbeite 10 (dh der Winsock2 lib).

Vielen Dank im Voraus!

+1

Wenn Sie wollen "schnelle" IPC unter Windows, warum Sockets verwenden? Vor allem TCP, das ziemlich viel Overhead hinzufügt (selbst wenn es lokal verwendet wird). Es muss eine Art geteilte In-Memory-Strukturen geben, die du benutzen könntest (vielleicht einfach geteilten Speicher mit einem geteilten Mutex zum Schutz, und ein paar geteilte Signale irgendeiner Art zu sagen, wenn ein Paket von beiden Seiten bereit ist) . –

+0

Ich sah Named Pipes, aber eine Menge Leute sagten, dass ihre Leistung ist etwa gleich. Soweit ich weiß, wenn Sie TCP lokal verwenden, vermeidet es den größten Teil der Overhead. –

+0

Gibt es einen Grund für die Verwendung, so kann Anrufe senden? Wie kann man die Daten serialisieren (zum Beispiel in einer Struktur) und dann einen einzelnen Sendeaufruf verwenden? – Jonas

Antwort

2

Sie sind wahrscheinlich die Strafe „Nagle-Algorithmus“ Leiden Siehe https://en.wikipedia.org/wiki/Nagle%27s_algorithm

Lange Rede kurzer Sinn, gibt es eine Verzögerung eingebaut, um TCP/IP mit dem Ziel, genügend Daten zu sammeln wert zu sein, ein Paket zu senden bevor das erste Paket gesendet wird.Es gibt eine TCP_NODELAY-Option, die Sie beim Öffnen des Sockets verwenden können, um dies zu deaktivieren, wenn es ein Problem für Sie ist.

Nachdem gesagt worden ist, wenn Leistung von entscheidender Bedeutung ist, ist es besser, mit Shared Memory für Inter-Prozess-Kommunikation statt Sockets.

+0

Irgendwelche Gedanken darüber, wie TCP_NODELAY reagiert, können also Anrufe senden? – Jonas

+0

Soweit ich weiß, wird es die ersten paar winzigen Pakete einfach nicht verzögern, bis genug Daten angesammelt sind, um es wert zu sein, gesendet zu werden. Also wird Ihr "TTFB" (time-to-first-byte) verkürzt. Das Zeit-zu-Letzt-Byte wird jedoch nicht beeinflusst. Wenn Sie also immer alle diese Daten senden, und wenn die andere Seite nichts zu tun hat, bis alle Daten angekommen sind, dann ist es nicht wirklich wichtig . In der Tat kann dies zu einer etwas schlechteren Leistung führen, da mehr Pakete ausgetauscht werden und jedes Paket einen geringen Overhead hat. –

Verwandte Themen