It is a gRPC mode that allows to stream data in both directions at the same time. It is useful for chats and games. It is quite similar to WebSockets. Communication between Server and Client is independent.

Example

// chat.proto  
  
syntax = "proto3";  
  
package chat;  
  
message ChatMessage {  
  string user = 1;  
  string message = 2;  
  string timestamp = 3;  
}  
  
service Chat {  
  rpc chatStream(stream ChatMessage) returns (stream ChatMessage);  // Bidirectional streaming  
}  

In this example, we define a ChatMessage that contains a user, a message, and a timestamp. The chatStream method allows both the client and the server to send a stream of ChatMessage objects to each other.

// server.ts  
import * as grpc from '@grpc/grpc-js';  
import * as protoLoader from '@grpc/proto-loader';  
import { ChatMessage } from './proto/chat';  // Import the necessary types  
  
// Load the .proto file  
const packageDefinition = protoLoader.loadSync('chat.proto', {  
  longs: String,  
  enums: String,  
  defaults: true,  
  oneofs: true,  
});  
  
const proto = grpc.loadPackageDefinition(packageDefinition) as any;  
  
// Create typed server implementation  
const chatService = {  
  chatStream: (call: grpc.ServerDuplexStream<ChatMessage, ChatMessage>) => {  
    call.on('data', (message: ChatMessage) => {  
      // When a message is received from the client, print it  
      console.log(`Received message from ${message.user}: ${message.message}`);  
  
      // Send a response back to the client  
      const timestamp = new Date().toISOString();  
      const responseMessage: ChatMessage = {  
        user: 'Server',  
        message: `Acknowledged: ${message.message}`,  
        timestamp,  
      };  
  
      // Write the response message to the stream  
      call.write(responseMessage);  
    });  
  
    call.on('end', () => {  
      console.log('Client has ended the stream.');  
      call.end(); // End the stream once the client stops sending messages  
    });  
  
    call.on('error', (err) => {  
      console.error('Error in chatStream:', err);  
    });  
  },  
};  
  
// Create and start the gRPC server  
const server = new grpc.Server();  
server.addService(proto.chat.Chat.service, chatService);  
server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {  
  console.log('gRPC server running on port 50051');  
  server.start();  
});  
  
  
// client.ts  
import * as grpc from '@grpc/grpc-js';  
import * as protoLoader from '@grpc/proto-loader';  
  
// Load the .proto file  
const packageDef = protoLoader.loadSync('chat.proto', {  
  longs: String,  
  enums: String,  
  defaults: true,  
  oneofs: true,  
});  
  
const grpcObject = grpc.loadPackageDefinition(packageDef) as any;  
const chatPackage = grpcObject.chat.Chat;  
  
const client = new chatPackage('localhost:50051', grpc.credentials.createInsecure());  
  
// Create a duplex stream for bidirectional communication  
const call = client.chatStream((error, response) => {  
  if (error) {  
    console.error('Error during stream:', error);  
    return;  
  }  
  
  // Handle incoming messages from the server  
  console.log('Server:', response.message);  
});  
  
// Sending messages to the server  
const sendMessage = (user: string, message: string) => {  
  const timestamp = new Date().toISOString();  
  const chatMessage = {  
    user,  
    message,  
    timestamp,  
  };  
  
  call.write(chatMessage);  // Write to the stream (send the message)  
};  
  
// Start sending messages  
sendMessage('User1', 'Hello, server!');  
sendMessage('User1', 'How are you?');  
  
// Receiving messages from the server  
call.on('data', (response) => {  
  console.log('Received from server:', response.message);  
});  
  
call.on('end', () => {  
  console.log('Server ended the stream');  
});  
  
call.on('error', (err) => {  
  console.error('Error in the client stream:', err);  
});  
  
  
Client sends: "Hello, server!"  
Server responds: "Acknowledged: Hello, server!"  
Client sends: "How are you?"  
Server responds: "Acknowledged: How are you?"