diff --git a/client/python/client.py b/client/python/client.py
index 22a9500ca713a90d2aa667bcce899c0b30431327..15f13e5b573b013fca79937d431559a331a2504b 100644
--- a/client/python/client.py
+++ b/client/python/client.py
@@ -2,16 +2,64 @@ import sys
 sys.path.insert(0, '../..')
 sys.path.insert(0, '../../shared/netcode')
 
+import queue
 import grpc
 from shared.netcode.netcode_pb2 import *
 from shared.netcode.netcode_pb2_grpc import NotifierComStub
 
+usage = "Usage:\n- Sender:\n  ./client.py 1\n- Receiver:\n  ./client.py 0"
+
+
 def sendMessage(stub, msg):
-    request = SendMessageRequest(message=msg)
+    request = Message(content=msg)
     response = stub.SendMessage(request)
 
 
 if __name__ == "__main__":
+    # Check enough args
+    if len(sys.argv) < 2:
+        print("Error: Not enough arguments.")
+        print(usage)
+        exit(1)
+
+    ########################################################################
+    # SETTINGS
+    ########################################################################
+    is_sender = sys.argv[1]
+    ########################################################################
+
+    # print info
+    print("-- SENDER --" if is_sender else "-- RECEIVER --")
+
     with grpc.insecure_channel('localhost:8080') as channel:
+        try:
+            grpc.channel_ready_future(channel).result(timeout=5)
+        except grpc.FutureTimeoutError:
+            print("Error: Connection to server failed.")
+            exit(1)
+
         stub = NotifierComStub(channel)
-        sendMessage(stub, "test")
+
+        if is_sender:
+            response = stub.OpenComm(OpenCommRequest(challenge=1))
+            print(response)
+
+            sendQueue = queue.SimpleQueue()
+            response_future = stub.SendMessage.future(iter(sendQueue.get, None))
+            sendQueue.put_nowait(Message(content="init test"))
+
+            print("Starting Prompt:")
+            while True:
+                text = input()
+                if text == "":
+                    print("Stopping...")
+                    break
+                print("Sending:", text)
+                sendQueue.put_nowait(Message(content=text))
+
+        else:
+            response = stub.AnswerComm(AnswerCommRequest(challenge=1))
+            print(response)
+
+            for message in stub.ReceiveMessage(Nothing()):
+                print(message.content)
diff --git a/protocol.md b/protocol.md
index a1fe44f0868c71d1ee4568995e6896463df03c97..6b5bd20b13d25c588ea9efc8d35013886bb51bbc 100644
--- a/protocol.md
+++ b/protocol.md
@@ -6,8 +6,8 @@
 
 1. Authenticate to the server and establish communication.
    1. A tells the server to open a communication.
-      1. A calculates the challenge.
-      2. A sends the challenge to the server.
+      2. A sends an id_code to the server.
+      3. A gets a comm_id from the server.
    2. B tells the server to answer A's communication request.
       1. B receives A's challenge.
       2. B answers the solution to the server.
@@ -15,4 +15,4 @@
 2. Generate and exchange an ephemeral key.
 3. Instantiate symmetric encryption using the ephemeral key.
 4. Authenticate each other directly.
-5. Check communication transcript (avoid malicious server).
\ No newline at end of file
+5. (?) Check communication transcript (avoid malicious server).
\ No newline at end of file
diff --git a/server/server.py b/server/server.py
index 28dba7704da115686af71c2c1868a5602f131166..b04427aacfd38f3811eb6a272161300eb1065b02 100644
--- a/server/server.py
+++ b/server/server.py
@@ -8,8 +8,25 @@ from shared.netcode.netcode_pb2_grpc import *
 
 
 class NotifierService(NotifierComServicer):
-    def SendMessage(self, request, context):
-        print(request.message)
+    def OpenComm(self, request, context):
+        # TODO: append id_code to list
+        # TODO: wait for id_code answered
+        # TODO: return comm_id
+        return CommResponse()
+
+    def AnswerComm(self, request, context):
+        # TODO: check if if_code can be answered
+        # TODO: return comm_id
+        return CommResponse()
+
+    def ReceiveMessage(self, request, context):
+        # TODO: read comm_id and wait for messages
+        yield Message(content="test")
+
+    def SendMessage(self, request_iterator, context):
+        for msg in request_iterator:
+            # TODO: read comm_id and route message
+            print(msg.content)
         return Nothing()
 
 
diff --git a/shared/netcode.proto b/shared/netcode.proto
index efb2582317b2e6cbf17503327044089a4fb16a7b..bae788f8f033a417893e20a0661c2cbbf8d0509e 100644
--- a/shared/netcode.proto
+++ b/shared/netcode.proto
@@ -1,12 +1,32 @@
 syntax = "proto3";
 package netcode;
 
-service NotifierCom {
-  rpc SendMessage (SendMessageRequest) returns (Nothing);
+service NotifierCommunication {
+  rpc Open (OpenRequest) returns (CommResponse);
+  rpc Answer (AnswerRequest) returns (CommResponse);
+  rpc SendMessage (stream Message) returns (Nothing);
+  rpc ReceiveMessage (ReceiveRequest) returns (stream Message);
 }
 
-message SendMessageRequest {
-  string message = 1;
+message ReceiveRequest {
+  uint64 comm_id = 1;
+}
+
+message Message {
+  uint64 comm_id = 1;
+  string content = 2;
+}
+
+message OpenRequest {
+  int64 id_code = 1;
+}
+
+message AnswerRequest {
+  int64 id_code = 1;
+}
+
+message CommResponse {
+  uint64 comm_id = 1;
 }
 
 message Nothing {