npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

socket-packet

v0.2.1

Published

A nodejs library to wrap TCP/UDP packets between a server and client

Downloads

21

Readme

JavaScript Style Guide Build Status Codacy Badge Codacy Badge GitHub issues GitHub stars npm

socket-packet

A nodejs library to wrap TCP/UDP packets between a server and client

Since you can never be sure of a data event being the full message, you may find yourself getting half packets, or even multiple packets at a time, and not being able to distinguish where a packet starts or ends.

This lib is intended to simplify this:

Installation

npm install socket-packet

How to use

import SocketPacket from 'socket-packet'

// Once you have a socket, or for example:
// const socket = new Socket()

SocketPacket.bind(socket)

socket.on('packet', packet => {
  if (packet === 'ping') {
    socket.send('pong')
  }
})

.bind(socket, logger, opts)

Binds socket-packet to an instance of a socket. This will attach the necessary logic to the socket for easy packet handling and sending.

  • socket: <Object> instance of a net.Socket
  • logger: {optional} <Object> instance of a winston or similar logger
  • opts: {optional} <Object> with any customized options for SocketPacket
SocketPacket.bind(socket, logger, opts)

Event: 'packet'

socket-packet adds a listener to the data event of the socket, "unwraps" the payload into their separate packets, and for each valid packet contained, emits the packet event

socket.on('packet', packet => {
  if (packet === 'ping') {
    socket.dispatch('pong')
  }
})

Event: 'error'

socket-packet emits error when encountering errors related to un/packaging messages, examples:

socket.on('error', error => {
  // handle error
})

.dispatch(data[,port, address, callback])

socket-packet binds a .dispatch function to the socket. Using this method will package the provided data/message and then write it to the socket

  • port: {optional} <number> UDP specific, not to be used with TCP, see dgram.send()
  • address: {optional} <string> UDP specific, not to be used with TCP, see dgram.send()
  • callback: {optional} <function> once the data has been flushed on the socket, this callback will be invoked, as expected when using net.Socket.write()
socket.dispatch('hello')
socket.dispatch('ping')
socket.dispatch({ hello: 'world'})

NB: although you are dispatching a JSON object, when it arrives on the other side of the socket, it would be a string/buffer ... You can use the packetParser on the other end of the socket to parse it as JSON; remember to use the packetStringifier to safely get a stringified version of the JSON object to write to the socket

Options

type

The type of socket being bound to. Options are:

  • tcp - Default
  • udp

startsWith

This library is all about packaging messages/data being transferred over a socket. Packages are wrapped with a default starting value -!@@!-, which is used to indicate the start of a new packet. If the server/client prefixes packets with a different value, be sure to set this to the same value

endsWith

This library is all about packaging messages/data being transferred over a socket. Packages are wrapped with a default ending value -@!!@-, which is used to indicate the end of a new packet. If the server/client suffixes packets with a different value, be sure to set this to the same value

encoding

The encoding to use when parsing/stringifying packets, default is'utf8' Caveat: if you use socket.setEncoding() and it does not match this encoding, problems may be experienced ... I have not yet tested this

packetStringifier

This function is used when socket.dispatch(data[, cb]) is invoked to stringify the message/data object before writing to the socket ... The default returns the packet as is, as a string:

opts = {
  packetStringifier: packet => packet && packet.toString()
}

if, for example, all packets are expected to be application/json, you can use this:

opts = {
  packetStringifier: packet => packet && JSON.stringify(packet)
}

packetParser

This function is used when the data event is emitted and a packet is extracted to parse the packet to a specified format ... The default dispatches the packet as is, as a string:

opts = {
  packetParser: packet => packet && packet.toString()
}

if, for example, all packets are expected to be application/json, you can use this:

opts = {
  packetParser: packet => packet && JSON.parse(packet)
}

Example

TCP

server.js:

import net from 'net'
import SocketPacket from 'socket-packet'
/* OR */
const net = require('net')
const SocketPacket = require('socket-packet')

const port = process.env.PORT || 8080
const host = process.env.HOST || 'localhost'

const server = net.createServer(socket => {
  console.log('Client connected')
  SocketPacket.bind(socket)

  socket.on('packet', packet => {
    switch (packet) {
      case 'ping': 
        console.log('ping received')

        setTimeout(() => {
          socket.dispatch('pong', () => {
            console.log('pong dispatched')
          })
        }, 500)
        break
      default:
        console.log('Unhandled packet received: ', packet)    
    }
  })

  socket.on('error', err => {
    console.log('Error:', err)
  })

  socket.on('end', () => {
    console.log('Client ended')
  })

  socket.on('close', hadError => {
    console.log(`Client disconnected (with error: ${hadError})`)
  })
})

server.listen(port, host, () => {
  const { address, port } = server.address()
  console.log(`Server started on ${address}:${port}`)
})

client.js:

import net from 'net'
import SocketPacket from 'socket-packet'
/* OR */
const net = require('net')
const SocketPacket = require('socket-packet')

const port = process.env.PORT || 8080
const host = process.env.HOST || 'localhost'

const client = net.createConnection({ port, host }, () => {
  console.log('connection established')
  SocketPacket.bind(client)
})

client.on('packet', packet => {
  switch (packet) {
    case 'pong':
      console.log('pong received')
      break
    default:
      console.log('Unhandled packet received: ', packet)
  }
})

client.on('error', err => {
  console.log('Error:' + err)
})

client.on('close', hasError => {
  console.log(`Connection closed (has error: ${!!hasError})`)
  clearInterval(interval)
})

const interval = setInterval(() => {
  client.dispatch('ping', () => {
    console.log('ping dispatched')
  })
}, 2000)

UDP

server.js:

import dgram from 'dgram'
import SocketPacket from 'socket-packet'
/* OR */
const dgram = require('dgram')
const SocketPacket = require('socket-packet')

const port = process.env.PORT || 9090
const host = process.env.HOST || 'localhost'

const serverSocket = dgram.createSocket({ type: 'udp4', sendBufferSize: 8192 })
SocketPacket.bind(serverSocket, null, { type: 'udp4' })

serverSocket.on('packet', (packet, rInfo) => {
  switch (packet) {
    case 'ping':
      console.log('ping received')

      serverSocket.dispatch('pong', rInfo.port, rInfo.address, () => {
        console.log('pong dispatched')
      })
      break
    default:
      console.log(`Unknown message received: ${packet}`)
      break
  }
})

serverSocket.on('error', err => {
  console.log('Server error:', err)
})

serverSocket.on('end', () => {
  console.log('Server ended')
})

serverSocket.on('close', hadError => {
  console.log('Server closed')
})

serverSocket.bind(port, host, () => {
  const { address, port } = serverSocket.address()
  console.log(`Server running on ${address}:${port}`)
})

client.js:

import net from 'net'
import SocketPacket from 'socket-packet'
/* OR */
const dgram = require('dgram')
const SocketPacket = require('socket-packet')

const port = process.env.PORT || 9091
const host = process.env.HOST || 'localhost'

const serverPort = process.env.SERVER_PORT || 9090
const serverHost = process.env.SERVER_HOST || 'localhost'

const clientSocket = dgram.createSocket({ type: 'udp4', sendBufferSize: 8192 })
SocketPacket.bind(clientSocket, null, { type: 'udp4' })

clientSocket.on('packet', packet => {
  switch (packet) {
    case 'pong':
      console.log('pong received')
      break
    default:
      console.log(`Unknown message received: ${packet}`)
      break
  }
})

clientSocket.on('error', err => {
  console.log('Client error:', err)
})

clientSocket.on('end', () => {
  console.log('Client ended')
})

clientSocket.on('close', hadError => {
  console.log('Client closed')
})

clientSocket.bind(port, host, () => {
  const { address, port } = clientSocket.address()
  console.log(`Client running on ${address}:${port}`)

  setInterval(() => {
    clientSocket.dispatch('ping', serverPort, serverHost, () => {
      console.log('ping dispatched')
    })
  }, 2000)
})

Caveats:

  • Please make sure you know about UDP length limits and how nodejs errors out when misconfigured. UDP has a min and max length per os. Please ensure you use safe values, else socket-packet will throw errors (as thrown by nodejs' udp module). You may notice that I used 8192 in my examples: I feel this value is a safe value all round, but you may use your own defined value