Writing a Client
00:00
In the previous lesson, I showed you how to use netstat
to see what was going on with the sockets on your machine. In this lesson, I’ll go bork once more, this time writing a client to go along with our Swedish server.
00:13 Creating a socket on the client side is a simpler version of what you’ve already seen on the server. You start out by creating a socket object the same way, specifying what kind of socket it will be.
00:23
Then you use the socket object to connect to the server, calling connect()
instead of bind()
. Like bind()
, this takes a host and port, but this time for the thing that you’re connecting to.
00:34 And then once you’ve done that, you’re ready to send and receive.
00:39
Speaking of sending, there are actually two ways of sending data along a socket. The sendall()
command is the one you likely want most of the time, which takes a chunk of data and sends it down the pipe.
00:49
Unless there’s an error, in which case there is an exception. sendall()
will take care of sending all your data regardless of how long it takes.
00:56
There’s also a lower level primitive called send()
. This doesn’t promise to send everything you give it. It decides how much to send. It returns the amount of stuff it did send, leaving it up to you to decide what to do with the rest.
01:10
Presumably, sendall()
is just calling this method in a loop until all bytes are sent. Let’s go write a borky client.
01:20
This is bork-client.py
. Like with the server, it imports the socket
module and defines an address and port. Note that this is the address and port of what the client is connecting to, not the port the client ends up using.
01:34 That gets automatically set once you’ve connected. Also like with the server, you create the socket telling it you want IP version 4 and a data stream,
01:44
and then instead of bind()
, you call connect()
. This takes a tuple, which is the remote address and port you want to connect to.
01:51
And that’s pretty much it. The connect()
call returns once the connection is established, so you’re free to send and receive data. For my simple case here, I send the ubiquitous “Hello, World!” and then wait for a reply, then exit the program.
02:06 Let’s try this sucker out.
02:09 Going to start the server and then run the client.
02:18 It more or less happens almost instantaneously. First, the client connected, resulting in the “Connected by” message. Note the port number there. This time I randomly got something easier to tell the difference from the server.
02:30 Remember that port gets assigned automatically when a client opens a connection. Once the connection got established, the client sent the “Hello, World!”, which you can tell by the server’s “Received” message.
02:42 The server then replied with the borkified response, which the client received and then terminated the connection. The server’s next attempt to get data resulted in an empty chunk, and so the server closed down as well.
02:59 So far, I’ve kind of glossed over something. If you weren’t paying close attention, you might have thought I was sending strings back and forth between the client and server, but I haven’t.
03:07 I’ve been sending bytes. Bytes and strings in Python are distinct types. What I’ve been doing so far has been using raw bytes through the byte strings syntax.
03:17
You do that with a b
prefix on a quoted item. This is text, but it isn’t a Python string, it’s a raw byte value. Strings in Python include encoding information, and that default is UTF-8.
03:33 So if you haven’t explicitly said otherwise when using a string, you’ve been using UTF-8. The tricky part of this is the first chunk of UTF-8 is fully compatible with the ASCII table, which is why I can type “Hello” as bytes and have it show up in the editor without any problem.
03:49
But just because I can type it in my editor doesn’t mean that Python isn’t doing other stuff with it. All strings have encodings associated with them, which means if you want to switch back and forth between strings and bytes, you need to use the encode()
and decode()
functions.
04:05 This might seem like a bit of a tangent, but I want to write a variation on our client that has a counter, and since that counter’s going to increment, it can’t hard code a byte string like before.
04:15 So now I’ve got to do some conversion. Let’s go look at that new client. This is my second client. Instead of just hard coding “Hello, World!”, this one tracks a counting value and sends it to the server.
04:28 I’ve moved from the Muppets to Sesame Street. One counting value. Ah, ah, ah. The first difference here is I’m grabbing a command-line argument, which will be the initial value of my counter.
04:40 Then I’m going to count out five values, sending each to the server, and here is where I convert that integer into a string.
04:49
Then inside the sendall()
, I use the built-in bytes()
function to convert the string to data. The second argument to bytes()
is the kind of encoding the string has, so it knows how to convert it.
05:02 Then once I’ve sent the value and received a response, I wait for one second before counting the next value.
05:08 Let’s try this out. This time I have three windows. In the top, I’ll start the server. Now in the second window, I’ll start the count client using a value of 100.
05:23 Ah, ah, ah, ah. The result I get back is 100, bork, bork, bork. Then 101, then 102. Through the magic of video editing, I can stretch that one-second pause as long as I like.
05:38 So don’t worry too much about the timing. I put in enough delay that if you’re trying this yourself, you’ve got time to do the next step. In the bottom window, I’m going to start another copy of count using 500 this time. And there’s my second.
05:55 Hmm. Well, that’s interesting. Our 100s keep going, but our 500 does nothing. Note how there isn’t even a connected message in the top window for our second counter.
06:06 And once the 100 sends its last packet, our server closes the connection, causing the reset error for our second copy of counter.
06:15 The problem here is our server code is only listening for a single connection, and that’s not terribly useful.
06:24 In the next lesson, I’ll show you how to deal with multiple connections.
Become a Member to join the conversation.