Why Do We Still Need HTTP and RPC When TCP Exists?
The article explains how TCP provides reliable byte‑stream transport but lacks message boundaries, how HTTP adds structured semantics with headers like Content‑Length, and why RPC frameworks such as gRPC are introduced to make remote calls feel like local method invocations, especially in modern microservice architectures.
TCP fundamentals and sticky‑packet issue
TCP provides reliable, connection‑oriented byte‑stream transport. It guarantees ordered delivery via a three‑way handshake, acknowledgments and retransmission. Because it transmits a continuous stream of bytes, it has no inherent message boundaries. The following code demonstrates that two consecutive writes may be received as a single concatenated string, illustrating the sticky‑packet problem:
// Sender writes two independent messages
socket.write("Hello");
socket.write("World");
// Receiver may get "HelloWorld" and cannot distinguish original boundariesDefining message boundaries is therefore the responsibility of the application‑layer protocol.
HTTP adds structured messages
HTTP defines a clear message format on top of TCP. The start line, headers and body separate messages. The Content‑Length header (or chunked transfer encoding) tells the receiver the exact body size, eliminating ambiguity. Example:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 48
{"name":"Alice","email":"[email protected]"}Standard methods (GET, POST, PUT, DELETE) and extensions (caching, content negotiation, state management) give semantics to the transmitted data. Thus HTTP solves “what to transmit” and “how to parse it”.
Why RPC on top of HTTP?
Calling a remote service via raw HTTP requires boilerplate: creating an HttpClient, setting headers, serializing request bodies, handling status codes and deserializing responses. The code example below shows the repetitive steps:
// HTTP client boilerplate
HttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("http://user-service/getUser");
post.setHeader("Content-Type", "application/json");
String jsonBody = "{\"user_id\": 123}";
post.setEntity(new StringEntity(jsonBody));
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == 200) {
String responseBody = EntityUtils.toString(response.getEntity());
User user = objectMapper.readValue(responseBody, User.class);
}
// Too many low‑level details to handle!Developers therefore seek a model where a remote call looks like a local method invocation.
RPC concept
Remote Procedure Call (RPC) is a calling paradigm, not a concrete protocol. Its goal is transparent remote invocation, e.g.:
User user = userService.getUser(123);Specific implementations such as gRPC, Thrift, or Dubbo provide the actual protocols. Correct phrasing is “use the gRPC protocol for RPC calls”, not “use the RPC protocol”.
Layer relationship between RPC and HTTP
RPC operates at the invocation layer, comparable to local method calls. HTTP is an application‑layer protocol. RPC can be built on top of HTTP (gRPC uses HTTP/2) or on custom TCP/UDP protocols, so they reside on different layers.
RPC protocol vs RPC framework
Protocol fundamentals
Message format – defines how a message starts, ends, and its header/body structure.
Serialization – specifies how data is encoded and decoded.
Transport rules – describe communication flow and interaction patterns.
Framework ecosystem
Core layer – implements the communication protocol.
Component layer – provides serialization, service discovery, load balancing, etc.
Governance layer – adds fault tolerance, monitoring, registry and other operational features.
Application layer – exposes transparent remote method calls to developers.
Performance advantages of RPC for internal service calls
Binary serialization formats such as Protobuf are much smaller and faster than JSON. The following comparison shows a JSON object (~40 bytes) versus its Protobuf binary representation (~11 bytes), a size reduction of over 70 % and noticeably higher serialization speed:
// JSON serialization (readable but larger)
{"id":123,"name":"Alice","age":30} // ~40 bytes
// Protobuf binary (compact and fast)
\x08\x7B\x12\x05Alice\x18\x1E // 11 bytesProtocol overhead is reduced by long‑lived connections (fewer TCP handshakes), multiplexing (better connection utilization) and header compression. RPC frameworks also design streamlined headers, binary encoding and employ zero‑copy techniques for high throughput.
HTTP for external API exposure
HTTP is universally supported across platforms, languages, browsers and devices. Common ports 80/443 are open, and mature toolchains (browsers, Postman, curl) simplify testing. A simple fetch call demonstrates ease of consumption:
fetch('/api/users/123')
.then(response => response.json())
.then(user => { displayUser(user); });Typical architecture practice
Modern internet companies separate internal and external traffic. Gateways handle cross‑cutting concerns and translate incoming HTTP requests to RPC calls for internal services. Internal services use high‑performance RPC frameworks (e.g., gRPC, Dubbo); external interfaces use HTTP/REST for compatibility.
Summary
TCP guarantees reliable byte‑stream transmission.
HTTP adds structured message boundaries and semantics.
RPC abstracts remote invocation, offering binary protocols and low‑overhead communication for internal services.
Best practice: use RPC frameworks (gRPC, Dubbo, etc.) for internal high‑performance calls and HTTP/REST for external APIs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
