Re:Introduction to TCP and Sockets (2001)
by dragontamer on Wednesday July 20, 2022 @02:12AM
(#32162077)
I feel like beginner programmers should experiment with the following concepts in order.
1. File I/O to plaintext files. fread/fwrite, or whatever equivalent is in your programming language (Python fd.read() or whatever) is your first step into I/O. Especially because you can open the file and read it yourself as a human.
2. Piped I/O using Unix Pipes and/or Fifos. Pipes (./program1 | ./program2) are by far the easiest interprocess communication mechanism. They're not very flexible, but they're obvious to understand once you have mastered simple File I/O.
3. TCP Sockets are the natural evolution from pipes. Your first TCP Server will not be socket/bind/accept, since this is a bit complicated. Instead, you should write nc -l (port number) | ./myprogram, where netcat does the heavy lifting for you and creates a listening server for ./myprogram. You then have the ability to write ./myclient (which communicates to netcat, and therefore to "myprogram").
4. You finalize this by writing the server side without the netcat training wheels, to learn the socket/bind/accept dance.
Re:Introduction to TCP and Sockets (2001)
by nly on Wednesday July 20, 2022 @03:16AM
(#32162544)
I disagree that TCP are an evolution of pipes. Pipes are unidirectional and have 2 file descriptors, which is way less confusing than TCPs behaviour with respect to EOF, shutdown and write()/read() error behaviour.
A socket API that gave you two unidirectional fd's for a TCP socket would have been a massive improvement.
With the POSIX API, you can duplicate the socket file descriptor, but calling shutdown() to close one direction of a file descriptor will actually close that direction on all file descriptors... unfortunate.
Re:Introduction to TCP and Sockets (2001)
by WJW on Wednesday July 20, 2022 @03:25AM
(#32162594)
TCP connections also have 2 file descriptors, they are just on different computers. It seems quite natural to me to think of a socket as two pipes joined together.
As with so many things in computing the abstraction leaks a bit when you get deeper into it but as a first intuition for beginners I think you could do way worse than "a socket is a bidirectional pipe to another computer".
I'm intrigued by your idea of making 2 file descriptors for each socket btw. Why would it be such an improvement in your opinion?
Re:Introduction to TCP and Sockets (2001)
by dragontamer on Wednesday July 20, 2022 @11:27AM
(#32167157)
> I disagree that TCP are an evolution of pipes. Pipes are unidirectional and have 2 file descriptors, which is way less confusing than TCPs behaviour with respect to EOF, shutdown and write()/read() error behaviour.
TCP is complicated. But "stream based sockets" aren't "just" TCP (ex: Unix domain sockets fixes all of the "glitches" of TCP).
The important bit of "sockets", in general, is the concept of:
1. "Accepting" file descriptor (creates new file descriptors whenever someone is "connecting" to you).
2. Multiplexing and "juggling" those descriptors.
TCP fits this model, though with some low level quirks. Unix Domain Sockets are arguably the place to start, but most beginner programmers wouldn't find that useful (they really want internet connections).
-------------
Its difficult to make a "server" off of one pipe. Maybe two pipes (first pipe accepts requests and divvys out new pipes to work off of). But no matter how you do it, its wonky.
A proper server needs that "accept" abstraction, which is completely missing from pipes.
Re:Introduction to TCP and Sockets (2001)
by nly on Wednesday July 20, 2022 @11:58AM
(#32167621)
> A proper server needs that "accept" abstraction, which is completely missing from pipes.
You can receive file descriptors over a UNIX socket, but yeah. That said I don't see why a file descriptor is a good abstraction for a listening socket in the first place when you don't read() or write() to it.
Re:Introduction to TCP and Sockets (2001)
by wruza on Wednesday July 20, 2022 @06:19AM
(#32163659)
In two-fds tcp, FIN/ACK, RST, timeouts and desire to stay as non-blocking as possible would still be a thing, so we’d have all the same functions and behaviors, only SHUT_RD|WR parameters would go away.
Pipes guarantee delivery if both sides agree, tcp doesn’t (but it tries hard asynchronously), that’s where the difference starts.
Re:Introduction to TCP and Sockets (2001)
by Waterluvian on Tuesday July 19, 2022 @11:41PM
(#32161139)
If I want to implement some rudimentary communications protocol between two machines in Rust, just for learning, is this where I should begin?
Edit: perhaps not quite. Seems like this lives “on top of” TCP or UDP. I should probably read through this then look for something like a “how to implement ICMP” guide.
Re:Introduction to TCP and Sockets (2001)
by Pr0ject217 on Wednesday July 20, 2022 @11:22AM
(#32167065)
Interesting. If you don't mind me asking, what kinds of things have you made talk to each other that weren't originally designed to talk to each other?
Re:Introduction to TCP and Sockets (2001)
by the_only_law on Wednesday July 20, 2022 @11:31AM
(#32167222)
Usually make retrocomupters talk to modern networks or modern computers talk to retro networks.
Admittedly I haven't programmed much in a while outside work, but have a number of backlogged projects including an H.320 (ISDN videoconferencing spec) to discord bridge.
Most of my ideas, are useless and kinda dumb, but fun.
Re:Introduction to TCP and Sockets (2001)
by cpach on Wednesday July 20, 2022 @06:01AM
(#32163537)
Sure. But keep in mind that some people readers here on HN are still beginners when it comes to TCP/IP. Maybe high school students, maybe they work in another field than tech, maybe they work in tech but with design, legal, HR etc etc. For those readers it could potentially be a useful and interesting resource.
1. File I/O to plaintext files. fread/fwrite, or whatever equivalent is in your programming language (Python fd.read() or whatever) is your first step into I/O. Especially because you can open the file and read it yourself as a human.
2. Piped I/O using Unix Pipes and/or Fifos. Pipes (./program1 | ./program2) are by far the easiest interprocess communication mechanism. They're not very flexible, but they're obvious to understand once you have mastered simple File I/O.
3. TCP Sockets are the natural evolution from pipes. Your first TCP Server will not be socket/bind/accept, since this is a bit complicated. Instead, you should write nc -l (port number) | ./myprogram, where netcat does the heavy lifting for you and creates a listening server for ./myprogram. You then have the ability to write ./myclient (which communicates to netcat, and therefore to "myprogram").
4. You finalize this by writing the server side without the netcat training wheels, to learn the socket/bind/accept dance.
A socket API that gave you two unidirectional fd's for a TCP socket would have been a massive improvement.
With the POSIX API, you can duplicate the socket file descriptor, but calling shutdown() to close one direction of a file descriptor will actually close that direction on all file descriptors... unfortunate.
As with so many things in computing the abstraction leaks a bit when you get deeper into it but as a first intuition for beginners I think you could do way worse than "a socket is a bidirectional pipe to another computer".
I'm intrigued by your idea of making 2 file descriptors for each socket btw. Why would it be such an improvement in your opinion?
TCP is complicated. But "stream based sockets" aren't "just" TCP (ex: Unix domain sockets fixes all of the "glitches" of TCP).
The important bit of "sockets", in general, is the concept of:
1. "Accepting" file descriptor (creates new file descriptors whenever someone is "connecting" to you).
2. Multiplexing and "juggling" those descriptors.
TCP fits this model, though with some low level quirks. Unix Domain Sockets are arguably the place to start, but most beginner programmers wouldn't find that useful (they really want internet connections).
-------------
Its difficult to make a "server" off of one pipe. Maybe two pipes (first pipe accepts requests and divvys out new pipes to work off of). But no matter how you do it, its wonky.
A proper server needs that "accept" abstraction, which is completely missing from pipes.
You can receive file descriptors over a UNIX socket, but yeah. That said I don't see why a file descriptor is a good abstraction for a listening socket in the first place when you don't read() or write() to it.
Pipes guarantee delivery if both sides agree, tcp doesn’t (but it tries hard asynchronously), that’s where the difference starts.
https://beej.us/guide/bgnet/
Very different format!
If anyone cares, 'Code' is a close second. Different styles and uses, I'm just judging on utility to me.
Edit: perhaps not quite. Seems like this lives “on top of” TCP or UDP. I should probably read through this then look for something like a “how to implement ICMP” guide.
Or maybe https://en.wikipedia.org/wiki/TCP/IP_Illustrated if you need to get down to the packet level.
A small-ish tcp/ip stack, in rust, that can use TAP so you're down in the weeds making the packets.
https://www.objc.io/issues/10-syncing-data/ip-tcp-http/
What attracts you to network programming?
Thank you.
Admittedly I haven't programmed much in a while outside work, but have a number of backlogged projects including an H.320 (ISDN videoconferencing spec) to discord bridge.
Most of my ideas, are useless and kinda dumb, but fun.