Skip to content

Instantly share code, notes, and snippets.

@kaushalmodi
Last active September 1, 2021 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaushalmodi/e75bd98468e75b6efdd7e2268bc68596 to your computer and use it in GitHub Desktop.
Save kaushalmodi/e75bd98468e75b6efdd7e2268bc68596 to your computer and use it in GitHub Desktop.
Nim client/server protobuf
import std/[os, threadpool, strformat, asyncdispatch, asyncnet]
import protocol_protobuf, streams
proc connect(socket: AsyncSocket, serverAddr: string) {.async.} =
echo &"Connecting to {serverAddr}"
await socket.connect(serverAddr, Port(7687))
echo "Connected!"
echo "Chat application started"
if paramCount() < 1:
quit("Please specify the server address and username, e.g. ./client localhost")
let
serverAddr = paramStr(1)
var
socket = newAsyncSocket()
asyncCheck connect(socket, serverAddr)
proc sendMessages() {.async.} =
var
(msg, msgLen) = createProtoMessage()
var
stream = newStringStream()
stream.write msg
echo "size of stream = ", sizeof(stream)
await socket.send(addr stream, sizeof(stream))
waitFor sendMessages()
# (1) First start the server in one terminal
# (2) *Then* run the client in another terminal, otherwise you will
# get "Software caused connection abort" exception.
import protobuf
# Define our protobuf specification and generate Nim code to use it
const protoSpec = """
syntax = "proto3";
message ExampleMessage {
int32 number = 1;
string text = 2;
}
"""
parseProto(protoSpec)
# Create our message
var msg = new ExampleMessage
msg.number = 10
msg.text = "Hello world"
# Make the ExampleMessage type visible in modules where this module is imported.
exportMessage ExampleMessage
proc createProtoMessage*(): (ExampleMessage, int) =
(msg, msg.len)
import std/[asyncdispatch, asyncnet, strformat]
import protocol_protobuf, streams
type
Client = ref object
socket: AsyncSocket
netAddr: string
id: int
connected: bool
Server = ref object
socket: AsyncSocket
clients: seq[Client]
proc newServer(): Server =
Server(socket: newAsyncSocket(), clients: @[])
proc `$`(c: Client): string =
&"{c.id} ({c.netAddr})"
var
server = newServer()
proc processMessages(s: Server, c: Client) {.async.} =
while true:
var
msgStream = newStringStream()
let
numBytes = await c.socket.recvInto(addr msgStream, 8)
echo "num bytes received = ", numBytes
if numBytes == 0:
echo &"{c} disconnected!"
c.connected = false
c.socket.close()
return
msgStream.setPosition(0)
var
msg = msgStream.readExampleMessage()
echo &"{c} sent: number = {msg.number}, text = {msg.text}"
proc loop(s: Server; port = 7687) {.async.} =
s.socket.bindAddr(Port(port))
s.socket.listen()
while true:
let
(netAddr, clientSocket) = await s.socket.acceptAddr()
echo &"Accepted connection from {netAddr}"
let
c = Client(socket: clientSocket,
netAddr: netAddr,
id: s.clients.len,
connected: true)
s.clients.add(c)
asyncCheck processMessages(s, c)
waitFor loop(server)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment