Skip to content

prnvsh/Lynk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lynk

Lynk is a lightweight chat and file-sharing tool that works over a Local Area Network (LAN) — a college Wi-Fi, a hostel network, an office network, or even your home Wi-Fi. It's built entirely from scratch with raw Python sockets: no Flask, no Django, no requests library. It was built as a course project to explore low-level networking fundamentals — manually parsing HTTP-style requests, managing TCP sockets, and designing a simple client-server protocol from the ground up.

Table of Contents

What is Lynk?

The basic idea:

  • One computer runs the server.
  • Other computers run a client — either a command-line version or a GUI window — and talk to that server.
  • Anyone who connects can create a room with a password, or join an existing room if they know the password.
  • Inside a room, people can send chat messages and upload/download files.

The password acts as a small privacy barrier: even if many people are on the same Wi-Fi (common on public networks), only those who know your room's password can read its messages or download its files.

Why does Lynk exist?

A few everyday situations it's meant to solve:

  • You're in class and need to share a PDF with your project teammates, but the Wi-Fi has no internet — only LAN. WhatsApp and Gmail are out.
  • You don't want to deal with Bluetooth (slow, pairing issues).
  • You don't want to pass around a pen drive.
  • You don't want an AirDrop-style broadcast where strangers nearby can see your file too.

Lynk gives you a tiny, private chatroom on the local network — friends on the same Wi-Fi join your room with a password and start chatting and sharing files, with no internet required.

Features

  1. Create a room with a password/create makes a new room. The password doubles as the room's identity.
  2. Join an existing room/join lets others into a room you've created.
  3. Send chat messages/send posts a message tagged with your name.
  4. Upload files/upload sends any file (image, PDF, zip, anything) into the room.
  5. Download files/download saves a file from the room to your computer by its index number.
  6. Poll for updates/poll asks the server "what's new since I last checked?" and shows only new messages/files.
  7. Two ways to use it — a command-line client (Client.py) and a graphical client (Ui.py, built with Tkinter).
  8. Auto-refreshing GUI — the GUI polls the server every 1.5 seconds, so messages appear without pressing a button.
  9. Inline download buttons — in the GUI, every shared file gets a real Download button embedded right in the chat.
  10. Multiple rooms at once — one server can host many independent rooms, each with its own messages and files.

How Lynk works

Lynk uses a client-server model with three programs:

File Role Who runs it?
Server.py Backend Host
Client.py Text-based chat client Terminal users
Ui.py Graphical chat client GUI users

The flow:

  1. The host runs Server.py, which starts listening on port 8080.
  2. The host shares their IP address (e.g. 192.168.1.5) with friends.
  3. Each friend opens Client.py or Ui.py, enters the host's IP, and creates or joins a room.
  4. When someone sends a message or file, it goes to the server.
  5. The server stores it in that room's list.
  6. Other people in the room poll the server periodically, and the server replies with whatever's new.

This is a polling model — clients keep asking "anything new?" instead of the server pushing updates. Polling is simpler to build than push-style updates (like WebSockets), which is why Lynk uses it.

The mini protocol

Clients and server talk using HTTP-like text requests sent over raw sockets — hand-parsed, no web framework involved.

A request looks like a simplified HTTP request:

GET /send?pwd=cs101&name=Alice&msg=hello+world HTTP/1.1
Host: localhost

A response looks like a simplified HTTP response:

HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 2

OK

Endpoints:

Path Method Query params What it does
/create GET pwd Make a new room
/join GET pwd Confirm a room exists with that password
/send GET pwd, name, msg Add a chat message to the room
/upload POST pwd, name, filename Upload a file (file bytes go in the request body)
/download GET pwd, idx Download the file at the given index
/poll GET pwd, since Get all messages/files added after since

How data is stored on the server

Everything lives in memory, in two Python dictionaries:

rooms = {}  # password -> list of items (chat messages and file notices)
files = {}  # password -> list of (filename, file_bytes)

The rooms dictionary — each entry is a list mixing two kinds of strings:

  • MSG:<name>:<message text> — a chat message
  • FILE:<name>:<filename>:<idx> — a file-share notice (the actual bytes live in files)

Example — room "cs101" might look like:

rooms["cs101"] = [
    "MSG:Alice:hey everyone",
    "MSG:Bob:hi alice",
    "FILE:Alice:notes.pdf:0",
    "MSG:Bob:got it, thanks"
]

The files dictionary — where the actual bytes of uploaded files are kept:

files["cs101"] = [
    ("notes.pdf", b"<raw pdf bytes>"),
]

The idx in a FILE: message is just the file's position in this list — idx=0 means the first file uploaded to that room.

Important: nothing is saved to disk. If you stop the server, all rooms, messages, and files disappear. This keeps the project simple and easy to read.

Requirements

  • Python 3.x (standard library only — no pip installs needed)
  • Tkinter (bundled with most Python installs; on some Linux distros you may need sudo apt install python3-tk)

Setup and running

Start the server:

python Server.py

You should see:

Server listening on port 8080

Leave this terminal running — don't close it.

Start the CLI client:

python Client.py

It will ask for the server IP. Type the host's IP and press Enter (leave blank if testing on the same machine).

Start the GUI client:

python Ui.py

A window appears. Type in the server IP, a password, and your name, then click Create Room or Join Room.

Using the CLI client

Available commands:

/create <password> <yourname>      create a room
/join   <password> <yourname>      join an existing room
/send   <message>                  send a chat message
/upload <filepath>                 upload a file
/download <idx> <savepath>         download file by index
/poll                              show new messages since last poll
/quit                              exit

Example session:

> /create cs101 Alice
Room created. You are in.
> /send hello everyone
(sent)
> /upload notes.pdf
(file uploaded)
> /poll
[Alice]: hello everyone
[Alice] shared file 'notes.pdf' (idx 0)
    -> use: /download 0 <savepath>
> /download 0 my_notes.pdf
Saved to my_notes.pdf
> /quit
bye

Key things to remember (CLI):

  • You must create or join a room before sending or uploading anything.
  • The CLI does not auto-refresh — you have to type /poll to see new activity.
  • /poll only shows what's new since your last poll, tracked via an internal last_seen counter.

Using the GUI client

Ui.py is the friendlier, button-based version of the same client, with two screens.

Screen 1 — Welcome screen: fields for Server IP (pre-filled with 127.0.0.1), Password, and Your name, plus Create Room / Join Room buttons. If something goes wrong (wrong password, room already exists, etc.), a red status message explains why.

Screen 2 — Chat screen: a chat box showing all messages and file notices, a Message field with a Send button, and a File path field with a Send File button. The chat box refreshes automatically every 1.5 seconds via poll_messages() calling itself with root.after(1500, poll_messages).

Inline download buttons: when someone shares a file, the GUI embeds a real Download button directly in the chat box next to the filename, using Tkinter's chat_box.window_create() — clicking it saves the file to your current folder under its original name.

Code walkthrough

Server.py

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(5)

This creates a TCP socket, marks it reusable (so restarts work smoothly), binds it to port 8080 on every network interface the host has (0.0.0.0), and allows up to 5 waiting connections.

The main loop, per connection:

  1. Accepts one client connection.
  2. Reads request headers, until it sees \r\n\r\n (end of headers).
  3. Reads the body, if Content-Length was given (used during file uploads), until that many bytes have arrived.
  4. Parses the request line to get the method (GET/POST) and path.
  5. Parses the query string — turns ?pwd=abc&name=Alice into a dictionary.
  6. Routes to the right action based on path (/create, /join, /send, etc.).
  7. Builds and sends a response, with Content-Length so the client knows how much to read.
  8. Closes the connection.

Client.py

A while True: loop reads commands from input() and turns them into HTTP-style requests. The most reusable piece is connect_to_server(request_str), which opens a socket, sends one request, and reads everything the server sends back until it closes the connection — with try/except catching the two most common failures (timeout, server not running) and printing friendly messages instead of stack traces.

The /upload logic is slightly different — it doesn't reuse connect_to_server because it needs to send two chunks (the request headers, then the raw file bytes), so it builds its own socket inline.

Ui.py

The GUI mirrors the CLI command-by-command, wired to buttons instead of typed commands:

CLI command GUI function
/create create_room()
/join join_room()
/send send_message()
/upload send_file()
/download download_file()
/poll poll_messages()

The key difference is poll_messages() — it isn't called by the user, it calls itself via root.after(1500, poll_messages), which tells Tkinter "run this again in 1500 ms." It also runs once before you've joined a room, in which case it just reschedules itself and does nothing — that's why my_pwd == "" is checked first.

show_chat_screen() wipes the welcome-screen widgets (widget.destroy() on each child of root) and rebuilds the layout for the chat screen.

Known limitations

This was built to learn networking fundamentals, not to be production-ready:

  • No encryption. Traffic (including room passwords) is sent in plaintext. Don't use this over an untrusted network or for sensitive data.
  • Password ≠ real authentication. Room "passwords" are just plain identifiers with no hashing or session tokens.
  • Single-threaded server. One client is handled at a time (a concurrency tradeoff kept deliberately simple); a slow client can block others.
  • No persistence. All rooms, messages, and files live in memory and are lost when the server restarts.
  • Minimal input escaping. Messages/filenames containing &, =, or % may not round-trip correctly through the query string.

Contributions or forks that address any of the above are welcome.

License

This project is licensed under the MIT License. See LICENSE.md for details.

About

Lightweight LAN chat & file sharing tool built from scratch with raw Python sockets no frameworks, just TCP and a hand-rolled HTTP-like protocol.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages