1. concept

    • Personally, it is the communication channel between client and server
    • Four attributes are required to determine a single socket
      • Server IP, server Port, client IP, client Port
    • Through these four attributes, it is not difficult to abstract the concept of passage in your mind, with the entrance and exit of the passage at both ends
  2. Python import socket

    1. Create a socket (base socket, specify protocol number, socket type, etc.)
      • s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    2. The service side
      • s.bind(address) address:(host,port)
      • S. flag (Limit on number of TCP connections)
      • S.acept () accepts a client TCP connection and returns (conn,address). Conn is the established socket object, i.e. a complete channel with known entry and exit, and address is the same format as address
    3. The client
      • S.connection (address) Establishes a connection, returns socket.error if an error occurs
    4. Public function
      • S.recv (bufsize[,flag]) receives information from the pipe,bufsize specifies the maximum amount of data to receive, and flag provides additional information about the message, which can usually be ignored.
      • S.end (string[,flag]) sends data, sending the data in string to the connected socket. The return value is the number of bytes to send, which may be less than the size of string bytes, meaning that the pipe is not large enough to send the data out at once.
      • S.c lose () close the socket
  3. Socket creation analysis starts by analyzing which code is blocked

    • S.acept () can’t wait until it gets stuck
    • S.end () must have data variables waiting for input
    • S.recv () is blocked if it can’t reach it

    Ah, good vexed, habit single process of I really drunk, this let a person how to write! Ak47 schematic item and loot added: Ak47 schematic item and loot added: What kind of dialogue do we want to create

    1:1 conversation

    • Code interaction is roughly this flow
      • Server :(omits s=s.socket.socket())
        • S. bind-> S. isten-> S. acept Ok, block here and wait for the connection
      • Client:
        • s.connect()
      • The connection is established, and the server side gets the conn channel object and client_adress from s.acept (), which we then save
      • Now start our data transmission, write web time, always is client attack, server suffer, this time reverse! (๑ • ̀ ㅂ ́) organisation ✧
      • Server:
        • While 1: MSG =input s.end (MSG)
      • client:
        • While 1: MSG =s.resv() print MSG //_ _ (: з < ")
      • This way, we can go crazy on the server, and then the client can print out the information we passed
    • After the great we think again, but this can only be unilaterally visited by the service side to ask the client, the client side even point reaction have no, boring, but two people are in that block of not yiyihu, how to do…..
    • Forget it. One process is not enough
    • Look at the following code
    # Server.py
    import socket
    import sys,os
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(("127.0.0.1",8000))
    s.listen(5)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    conn,address=s.accept()
    Start the child process and ask the son for help
    pid=os.fork()
    if(pid>0):
        Read the input and send it to client
        while 1:
            msg=sys.stdin.readline()
            if msg == "quit":
                sys.exit()
            conn.send(bytes(msg,encoding="utf-8"))
    else:
        while 1:
            log_file=open('./client_input.log'.'a')
            msg=conn.recv(1024) 
            print ("client:"+msg.decode('utf-8'))
            log_file.write(msg.decode('utf-8'))
            if msg == "bye":
                log_file.close()
                sys.exit()
    # Client.py
    import socket
    import sys,os
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect(("127.0.0.1",8000))
    
    pid=os.fork()
    if(pid>0):
        while 1:
            msg=sys.stdin.readline()
            if msg == "quit":
                sys.exit()
            s.send(msg.encode('utf-8'))
    else:
        while 1:
            log_file=open('./server_input.log'.'a')
            msg=s.recv(1024) 
            print ("server:"+msg.decode('utf-8'))
            log_file.write(msg.decode('utf-8'))
            if msg == "bye":
                log_file.close()
                sys.exit()
    
    Copy the code
    • Let’s see how it works

    • Oh, this is wonderful

    Multiplayer chat room

    • Let’s do a little bit of status 1.Everyone knows our server address and port.They don't know each other's addresses or portsSo, socket setup,Can only exist between server and client.Clients cannot be connected to each other2. So we have a premise: our server can connect with everyone, if we want to make a chat room, what functions are needed?
      • A user sends a message to the server, a multiplayer chat room for what? Of course, it’s about getting other people to pick up on this person’s message, in short, sending a message from a person to us on the server, broadcasting it to other people in the chat room

      • Sending messages to a single client requires us to store chat channels with that client, known as sockets. What about broadcast messages? We’re going to have to store all of these pipes, and one pipe gets a message and broadcasts it out

      • The first step is to join the chat room. Our previous code, Accept, will not call this method, that is, the server will not accept the new client connect. How to solve this problem? We’re going to listen to accept, of course, and we’re going to generate a new socket when we get a return value, and we’re going to store that socket in our user list, so we’re going to record all the channels

      • Once we have access to all users, we also need to listen for all messages sent at the same time, and then perform the steps we described earlier, receiving user messages and then broadcasting them

      • Here’s the code. Because we want to listen for both Accept and RECV, we select the select library (select is a magic thing)

        import socket, select
        
        # broadcast function
        def broadcast_data (sock, message):
         	Do not broadcast to senders and accept
            for socket in CONNECTION_LIST:
                ifsocket ! = server_socket and socket ! = sock : try : socket.send(message) except : socket.close() CONNECTION_LIST.remove(socket)if __name__ == "__main__":
        
            Listen to the list, including the user list and accept events
            CONNECTION_LIST = []
            RECV_BUFFER = 4096 # Advisable to keep it as an exponent of 2
            PORT = 5000
        
            server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        
            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server_socket.bind(("0.0.0.0", PORT))
            server_socket.listen(10)
            Listen for the return of accept
            CONNECTION_LIST.append(server_socket)
        
            print "Chat server started on port " + str(PORT)
        
            while 1:
                If an event is triggered in the listener list, the result will be returned to read_sockets, telling us what message is coming in
                read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
         		 # Then we can do the following
                for sock in read_sockets:
                    If the message is sent from server_socket, a new connection has arrived
                    if sock == server_socket:
                        sockfd, addr = server_socket.accept()
                        CONNECTION_LIST.append(sockfd)
                        print "Client (%s, %s) connected" % addr
                        broadcast_data(sockfd, "[%s:%s] entered room\n" % addr)
        
                    else:
                       # Message coming
                        try:
                            data = sock.recv(RECV_BUFFER)
                            if data:
                                broadcast_data(sock, "\r" + '<' + str(sock.getpeername()) + '>' + data)
                                # RecV receives empty messages when the client is down, so close the socket
                            if not data :
                                broadcast_data(sock, "\r" + '<' + str(sock.getpeername()) + '>' + "Offline")
                                sock.close()
                        except:
                            broadcast_data(sock, "Client (%s, %s) is offline" % addr)
                            print "Client (%s, %s) is offline" % addr
                            sock.close()
                            CONNECTION_LIST.remove(sock)
                            continue
            server_socket.close()
        #client.py
        import socket, select, string, sys,signal
        def prompt() :
            sys.stdout.write('<You> ')
            sys.stdout.flush()
        def sighandler(signum,frame):
                sys.stdout.write("Shutdown Server...... \n")
                Send the connection message to the client and close the socket
                # close listen
                sys.stdout.flush()
                sys.exit()
        if __name__ == "__main__":
            signal.signal(signal.SIGINT,sighandler)
            signal.signal(signal.SIGHUP,sighandler)
            signal.signal(signal.SIGTERM, sighandler)
            if(len(sys.argv) < 3) :
                print('Usage : python telnet.py hostname port')
                sys.exit()
        	host = sys.argv[1]
            port = int(sys.argv[2])
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(2)
            try :
                s.connect((host, port))
            except :
                print('Unable to connect')
                sys.exit()
            print('Connected to remote host. Start sending messages')
            prompt()
            while 1:
                rlist = [sys.stdin,s]
                read_list, write_list, error_list = select.select(rlist , [], [])
                for sock in read_list:
                    if sock == s:
                        data = sock.recv(4096)
                        if not data :
                            print('\nDisconnected from chat server')
                            sys.exit()
                        else :
                            print (data.decode('utf-8'))
                            sys.stdin.flush()
                            prompt()
                    else :
                        msg = sys.stdin.readline()
                        s.send(msg.encode('utf-8'))
                        prompt()
        Copy the code
    • If you look at the code, you’ll see that this is single-process writing. A select helps us solve the problem of blocking by concentrating many blocks into one block, which makes the function possible
    • However, in this single-process mode, personal analysis will have the problem of untimely response. After all, a process is responsible for forwarding multiple messages. If there are too many messages, the response speed will be reduced in the case of for loop
    • So there’s another model that you can use, and a little bit of imagination:

Multithreaded mode

  • Is still a process for continuously accept user connection request, but when handling after it receives a request to change, we open a thread to responsible for the new channel news listening and send, before the process to accept to the new user to connect to the user list stored in a place accessible to all threads (I know redis, This way, we create a dedicated thread for each user to receive and forward messages from that user, and the response speed problem is solved
Refer to the article: [Python Socket programming example program - chat rooms By -- hazir] (https://www.cnblogs.com/hazir/p/python_chat_room.html)Copy the code