2016-07-05 1 views
2

SSL/TLS 용 OpenSSL을 사용하는 네트워킹 서버를 작성했습니다. 서버는 대량의 데이터를 송수신하고 중간에 다양한 변환을 수행합니다. 성능상의 이유로 변환은 값 비싼 메모리 이동 (memcpy() 등)을 피하는 벡터 정보 (POSIX의 iovec 참조)를 사용하여 주로 수행됩니다. 데이터를 보낼 준비가되면, 나는이 벡터들을 사용하여 메모리로부터 데이터를 모으는 writev() POSIX 함수를 사용하고, 그것을 일반적으로 하나의 네트워크 패킷으로 보냅니다.여러 개의 버퍼에서 OpenSSL SSL_write/SSL_writev

이제 OpenSSL은 내가 아는 한 OpenSSL이 SSL_write() 기능 만 제공하기 때문에 전적으로 가능하지 않습니다. 즉, 보내려는 모든 벡터 항목에 대해이 함수를 호출해야한다는 의미입니다. 유감스럽게도 모든 벡터화 된 데이터 덩어리가 자체 SSL 프레임으로 전송되므로 원치 않는 불필요한 네트워크 오버 헤드가 발생합니다.

제 질문은 SSL_writev()가 writev()와 같은가요? 또는 일반적으로 OpenSSL에서 SSL_write() 데이터를 보내지 않고 한 SSL 응용 프로그램 레코드 (유형 22)에 저장하고 (물론 플러시() 함수를 사용하지 않고) stash 할 수있는 방법이 있습니까?

편집 : 아래에 설명 된 것처럼 실행 가능한 접근 방식은 마지막 단일 SSL_write() 호출 이전에 벡터화 된 데이터를 큰 청크로 통합하는 것입니다. 그러나 오버 헤드가 2 개의 사본으로 연결됩니다 (통합 중 1 위, SSL_write()가 AES 암호화를 수행 할 때 두 번째). 이론적 인 SSL_writev() 호출은이 오버 헤드를 발생시키지 않습니다.

+0

"필업"기능이 필요하다고 생각합니다. 즉, 여러 개의 버퍼를 하나로 결합한 것입니다. – jww

+0

그게 바로 오늘 제가하는 일입니다. 그러나 그것은 꽤 비싸지 만 메모리에서 많은 양의 데이터를 이동시킵니다. –

+0

큰 덩어리가 TCP 오버 헤드 비용을 상환하는 것처럼 보입니다. 어쩌면 큰 데이터에 대해 별도의 쓰기를 허용하고 작은 데이터 만 "끌어 올리십시오". 또한,'-march = native'와'-O3'으로 컴파일한다면, 현대의 하드웨어에'memcpy'와'memmove'의 SSE4와 AVX 버전을 가져와야합니다. 한 번에 16, 32 및 64 바이트를 이동하기 때문에 번개가 빠릅니다. – jww

답변

0

이렇게하려면 BIO_f_buffer()을 사용할 수 있습니다. 네트워크 레이어 BIO를 BIO_f_buffer() 필터 BIO로 감싸고 SSL 개체에 대한 쓰기 BIO로 설정하십시오. 이렇게하면 버퍼에 플러시 할 때까지 버퍼에 남아있는 모든 데이터가 기록됩니다.

+0

BTW, 핸드 셰이크가 완료 될 때까지 기다리는 것이 좋습니다. 그렇지 않으면 교환되는 핸드 셰이크 메시지의 각 비행에 대해 "플러시"명령을 수동으로 실행해야합니다. –

+0

동의하지만 SSL_write를 호출 할 때마다 SSL 응용 프로그램 레코드 (유형 23)가 생성됩니다. 이는 원하지 않는 원치 않는 네트워크 오버 헤드를 의미합니다. –

+0

예 - 귀하의 설명에 따르면 귀하의 주된 관심사는 여러 네트워크 * 패킷 *을 피하는 것이었지만 그렇게 할 것입니다. 이는 TLS 레코드와 다릅니다. 여러 레코드가 단일 TCP 패킷 내에 포함되거나 여러 레코드로 분할 될 수 있습니다. 버퍼링과 플러시를 통해 네트워크 계층에 가능한 가장 효율적인 방법으로 네트워크를 통해 데이터를 전송할 수있는 최상의 기회를 제공합니다. 그런 다음 오버 헤드는 추가 레코드 헤더 바이트 (5 바이트) + MAC 크기 (암호 조합에 따라 다름)로 제한됩니다. 당신의 목표가 레코드의 수를 줄이는 것이라면 ... –