• Sockets on the server - lets look at the steps that are required to make a generic server.


  • And the server is also going to have to create a socket, but it has a bit of a different sequence of steps than what you see in a client.


  • First a server process running on your machine needs to sit there and wait for requests to come in


  • It listens for requests, waits for requests, when a request comes in, it receives the request, processes the request, gets the results, and then sends the results back.


  • So a server's bit of a different thing than a client.


  • So the first thing a server is going to have to do is create a socket that it's listening to, a local socket.


  • Then it's gottabind the socket to an IP address and port.


  • So when you create the socket at first, it's just floating there, not connected to anything. It needs to be associated with a particular port and IP address of the remote thing that it's connecting to.


  • Then once it's associated with the socket, it's gotta listen to that socket. So listening means just sitting there and waiting for a message to come in.


  • Now then once the message comes in, it's got to accept the connection


  • So once the connection is made, the client sends some data and the server receives that data, so it receive a request. It processes a request and sends the response, so it sends data back along the same connection to the client.


  • So lets go through some of the steps, what the code would look like.


  •  
    mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    mysock.bind("",1234)
    mysock.listen(5)
    conn,addr= mysock.accept()
    
    
  • The first thing you are going to do is you are going to create the socket. And then you're going to bind the socket.


  • So, the first line of code, mysock = socket.socket, it calls that function socket which creates a socket. And actually, that first line of code is the same as what goes on on the client to create the socket.


  • But, the next line is different. You have to bind the socket to an IP address and a port. Now the port number we are using here is 1234.


  • Notice that if I were making a web server or something like that, if I were making a web server or something like that I could actually use Port 80, for instance, because I know that's for web traffic and so on. In this case, I'm using an arbitrary port 1234, just because it's out of the way and it's not associated with anything.


  • The first argument is the host that you want to associate it with, the other host, the host that you're connecting to.


  • If you dont know which host you are connecting to, you pass as an argument, quotes. And, what that allows it to receive from any host. So you just pass it nothing for the host.


  • Okay now once it's bound, you're going to want to listen to the socket and then accept any connections that come in.


  • Notice that mysock.listen() takes an argument, a number. That number is called a backlog. That's the number of requests allowed to wait for service.


  • How many other clients can be waiting in line for you to finish serving until they get served this is backlog


  • It basically tells you how long the waiting line is going to be for the clients. So then the next line we call accept().


  • So you call mysock.accept(), this returns two things, so notice that it says conn, address.


  • The first thing that returns is the connection. You need this connection to receive data and to send data.


  • The server's going to need to do that


  • The addr is the address it is connected to- the IP address and the port number.


  • Now the port number we know because we bound to that port, but the IP address we wouldn't know until you call accept(), and then the IP, the address is going to contain the IP address of the client that's connected to you.


  • So now you have this connection connection is what you're going to use to receive data on and send a response back.


  • We'll talk about how to make it a live server, basically a server you want to stay alive, to continue to do its job over time - Sending and receiving.


  • So in our generic server, its job is basically to wait for connections. when it gets one, it accepts it. It accepts whatever data comes in on the socket, then, it takes that and sends it back.


  •  
    data = conn.recv(1000)
    conn.sendall(data)
    conn.close()
    mysock.close()
    
    
  • Code above is an echo server - just receives a message and then sends the same thing right back to the client.


  • So, it's a dumb server, but you can imagine putting in something more interesting if you wanted to that does something, receives the data, processes it, and sends the result back.


  • But typically you want a live server. So a live server is a server that doesn't just receive one message, send this response back, do that once and then go to sleep, an end.


  • Usually a server is a program that stays alive for a long period of time. Waiting for messages, and it receives a message, it does something, it sends a response, and waits for the next one, and it continues. In fact, it generally continues that forever.


  • So here's, here's how we modify the code slightly to do that.


  •  
    while True:
        conn, addr = mysock.accept()
        data = conn.recv(1000)
        if not data:
            break
        conn.sendall(data)
    
    conn.close()
    mysock.close()
    
    
  • Basically, it's similar to what we just saw except a while True, that's an infinite loop because True is always True. So what it does is, inside the loop it accepts a connection.


  • It retains the connection and the address.


  • Then we call receive on that connection to receive the data on that connection. Then if not data, we break.


  • So the idea there is that if we don't receive any data on the connection, then we know that the communication is done and we can just break out of this whole loop.


  • But if there is data then you say conn.sendall(data).


  • You just do what we want to do send the response back.


  • Presumably if it was a more interesting server it would do processing first then send the result back.


  • But we send the data back, and then we go back into the loop waiting to accept the next connection.


  • So, or not the next connection, but waiting to accept the next message.


  • And then outside the loop, we close a connection, and we close a socket.


  • So, that's just an example of a live server, how you make it so it stays alive over a period of time. And this is much more typical of a server. Infinite loop and connections close when no data is received.


  • So full server programs. So this is just the whole program put together, top to bottom,


  •  
    import system
    import sys
    
    
    mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    try:
        mysock.bind("",1234)
    except:
        print("Failed to send")
        sys.exit()
        
    mysock.listen(5)
    
    while True:
        conn, addr = mysock.accept()
        data = conn.recv(1000)
        if not data:
            break
        conn.sendall(data)
    
    conn.close()
    mysock.close()
    
    
  • Controlling a device over the Internet, it's the Internet of things,


  • Maybe you want to automate your home, control a device in your home remotely.


  • We've talked about socket based clients and servers, we have the tools to start doing that.


  • So the idea here is we want to send commands to a Raspberry PI and then have the Raspberry Pi do something in the real world. Now maybe that something is turning off and on a light in your house or moving a knife across somebody's vein or something like this.


  • Even though we're not going to to do this in this example, you can send data the other way, too. Sensor data can go from the Raspberry Pi to your remote device.


  • We're going to make a really simple system, an Internet controlled LED, just a light. Signal goes through the network, the internet, to your Raspberry Pi, sending a command to your Raspberry Pi and then it tells it to turn the LED off or on. The Raspberry Pi is wired directly to the LED. And it turns it off or on according to the remote commands.


  • Now notice that once we do this we can expand this to do anything based on any kind of message but as a demo we're just going to do this simple thing.


  • Basically what's happening in this is, that the Raspberry Pi is a server. It's sitting there waiting for a request, on and off. And some client is going to connect to the Raspberry Pi server, and if the Raspberry Pi sees that the request isn't on, it will turn the LED on.


  • So the LED itself is the resource that the server is protecting. Since the Raspberry Pi is acting as a server, we're going to basically take that generic server code that we just looked at in a previously and we're going to modify it ever so slightly to control this LED.


  •  
    import system
    import sys
    
    
    mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    try:
        mysock.bind("",1234)
    except:
        print("Failed to send")
        sys.exit()
        
    mysock.listen(5)
    
    while True:
        conn, addr = mysock.accept()
        data = conn.recv(1000)
        if not data:
            break
        if data ==b'on'
            GPIO.output(13,TRUE)
        if data ==b'off'
            GPIO.output(13,FALSE)
    conn.close()
    mysock.close()
    
    
  • At the top line there's an infinite loop. We say we accept the connection. We get this connection back. The next line we receive data. So we say conn. receive data, receive request.


  • Now in our model this request is going to be one of two things. It's going to be either an on or an off. Right, it's going to be the word on or the word off. So, if there's no data it breaks the connection


  • But if there's data, if the data equals on, then GPIO.output 13 equals true,


  • Now I'm assuming here that pin 13 is wired to the LED. In order for this to work, we have to take in the LED, wire it in a resistor to pin 13


  • So we wire it to pin 13, GPIO.output(13, true) will turn that LED on. Then if data equals off, then it's going to to say it's going to to take pin 13 to turn it off, to make it false, which will turn the LED off.


  • When we say data equals on its data equals b on. And data equals b off.


  • Because the data, the result returned from the receive function is not a string. It's what's called a byte array. A byte array is actually, it's an array, a list of bytes


  • Which is, actually in C equivalent to a string. But in Python those are actually different structures or different types of objects.


  • So what you need to do is you put that b in front of the string.


  • The simple shorthand for turning a string into a byte array is putting a b in front of it.


  • So if you say b on, that is the byte array which is equivalent to the string on. And then b off is the byte array which is equivalent to the string off.


  • I need to convert it into a byte array just so I can compare it to the data because the data's a byte array.