Hướng dẫn trò chuyện ngang hàng python

Vui lòng truy cập /cplusplus/sockets_server_client. php cho khái niệm chung về lập trình Mạng, TCP/IP/, ổ cắm, v.v.

Để biết thêm các mẫu đơn giản hơn, vui lòng truy cập chương máy chủ/máy khách cơ bản. Lập trình mạng Python

Trong chương này, chúng ta sẽ tạo một máy chủ trò chuyện. Máy chủ giống như một người trung gian giữa các khách hàng. Nó có thể xếp hàng lên đến 10 khách hàng. Máy chủ phát bất kỳ tin nhắn nào từ máy khách đến những người tham gia khác. Vì vậy, máy chủ cung cấp một loại phòng trò chuyện

Trong đoạn mã trò chuyện này, máy chủ đang xử lý các ổ cắm ở chế độ không chặn bằng cách chọn. phương thức chọn []

ready_to_read, ready_to_write, in_error = \
               select.select[
                  potential_readers,
                  potential_writers,
                  potential_errs,
                  timeout]

Chúng tôi vượt qua select[] ba danh sách

  1. cái đầu tiên chứa tất cả các ổ cắm mà chúng tôi có thể muốn thử đọc
  2. thứ hai là tất cả các ổ cắm mà chúng tôi có thể muốn thử ghi vào
  3. những cái cuối cùng [thường để trống] mà chúng tôi muốn kiểm tra lỗi

Mặc dù bản thân select[] là một cuộc gọi chặn [nó đang chờ hoàn thành I/O], chúng ta có thể cho nó thời gian chờ. Trong mã, chúng tôi đặt time_out = 0 và nó sẽ thăm dò ý kiến ​​​​và không bao giờ chặn

Trên thực tế, chức năng select[] giám sát tất cả các ổ cắm máy khách và ổ cắm máy chủ để biết hoạt động có thể đọc được. Nếu bất kỳ ổ cắm máy khách nào có thể đọc được thì điều đó có nghĩa là một trong những máy khách trò chuyện đã gửi tin nhắn

Khi hàm select trả về, ready_to_read sẽ chứa đầy một mảng bao gồm tất cả các bộ mô tả ổ cắm có thể đọc được

Trong mã, chúng ta đang giải quyết hai trường hợp

  1. Nếu ổ cắm chính có thể đọc được, máy chủ sẽ chấp nhận kết nối mới
  2. Nếu bất kỳ ổ cắm máy khách nào có thể đọc được, máy chủ sẽ đọc tin nhắn và phát lại cho tất cả các máy khách ngoại trừ người gửi tin nhắn

Đây là mã máy chủ. chat_server. py

# chat_server.py
 
import sys
import socket
import select

HOST = '' 
SOCKET_LIST = []
RECV_BUFFER = 4096 
PORT = 9009

def chat_server[]:

    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[10]
 
    # add server socket object to the list of readable connections
    SOCKET_LIST.append[server_socket]
 
    print "Chat server started on port " + str[PORT]
 
    while 1:

        # get the list sockets which are ready to be read through select
        # 4th arg, time_out  = 0 : poll and never block
        ready_to_read,ready_to_write,in_error = select.select[SOCKET_LIST,[],[],0]
      
        for sock in ready_to_read:
            # a new connection request recieved
            if sock == server_socket: 
                sockfd, addr = server_socket.accept[]
                SOCKET_LIST.append[sockfd]
                print "Client [%s, %s] connected" % addr
                 
                broadcast[server_socket, sockfd, "[%s:%s] entered our chatting room\n" % addr]
             
            # a message from a client, not a new connection
            else:
                # process data recieved from client, 
                try:
                    # receiving data from the socket.
                    data = sock.recv[RECV_BUFFER]
                    if data:
                        # there is something in the socket
                        broadcast[server_socket, sock, "\r" + '[' + str[sock.getpeername[]] + '] ' + data]  
                    else:
                        # remove the socket that's broken    
                        if sock in SOCKET_LIST:
                            SOCKET_LIST.remove[sock]

                        # at this stage, no data means probably the connection has been broken
                        broadcast[server_socket, sock, "Client [%s, %s] is offline\n" % addr] 

                # exception 
                except:
                    broadcast[server_socket, sock, "Client [%s, %s] is offline\n" % addr]
                    continue

    server_socket.close[]
    
# broadcast chat messages to all connected clients
def broadcast [server_socket, sock, message]:
    for socket in SOCKET_LIST:
        # send the message only to peer
        if socket != server_socket and socket != sock :
            try :
                socket.send[message]
            except :
                # broken socket connection
                socket.close[]
                # broken socket, remove it
                if socket in SOCKET_LIST:
                    SOCKET_LIST.remove[socket]
 
if __name__ == "__main__":

    sys.exit[chat_server[]]         

Có sự mơ hồ về cách chúng tôi phát hiện xem kết nối có bị hỏng hay không

Đây là một đoạn trích từ http. // tài liệu. con trăn. org/2/howto/ổ cắm. html

"Khi recv[] trả về 0 byte, điều đó có nghĩa là phía bên kia đã đóng [hoặc đang trong quá trình đóng] kết nối. Bạn sẽ không nhận được thêm bất kỳ dữ liệu nào trên kết nối này. Bao giờ. Bạn có thể gửi dữ liệu thành công. "

"Một giao thức như HTTP chỉ sử dụng một ổ cắm cho một lần truyền. Máy khách gửi yêu cầu, sau đó đọc phản hồi. Đó là nó. Ổ cắm bị loại bỏ. Điều này có nghĩa là máy khách có thể phát hiện phần cuối của câu trả lời bằng cách nhận 0 byte. "

"Nhưng nếu bạn định sử dụng lại ổ cắm của mình để chuyển tiếp, bạn cần nhận ra rằng không có EOT trên ổ cắm. tôi lặp lại. nếu một ổ cắm gửi hoặc recv[] trả về sau khi xử lý 0 byte, thì kết nối đã bị hỏng. Nếu kết nối không bị ngắt, bạn có thể đợi recv[] mãi mãi, vì ổ cắm sẽ không cho bạn biết rằng không còn gì để đọc [hiện tại]. "

Vì vậy, trong mã, chúng tôi coi kết nối bị tắt khi chúng tôi không thấy thêm dữ liệu nào từ ổ cắm ready_to_read

           
# process data recieved from client, 
try:
    # receiving data from the socket.
    data = sock.recv[RECV_BUFFER]
    if data:
        # there is something in the socket
        broadcast[server_socket, sock, "\r" + '[' + str[sock.getpeername[]] + '] ' + data]  
    else:
        # remove the socket that's broken    
        if sock in SOCKET_LIST:
            SOCKET_LIST.remove[sock]

        # at this stage, no data means probably the connection has been broken
        broadcast[server_socket, sock, "Client [%s, %s] is offline\n" % addr] 

Đây là mã khách hàng. chat_client. py

# chat_client.py

import sys
import socket
import select
 
def chat_client[]:
    if[len[sys.argv] < 3] :
        print 'Usage : python chat_client.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]
     
    # connect to remote host
    try :
        s.connect[[host, port]]
    except :
        print 'Unable to connect'
        sys.exit[]
     
    print 'Connected to remote host. You can start sending messages'
    sys.stdout.write['[Me] ']; sys.stdout.flush[]
     
    while 1:
        socket_list = [sys.stdin, s]
         
        # Get the list sockets which are readable
        ready_to_read,ready_to_write,in_error = select.select[socket_list , [], []]
         
        for sock in ready_to_read:             
            if sock == s:
                # incoming message from remote server, s
                data = sock.recv[4096]
                if not data :
                    print '\nDisconnected from chat server'
                    sys.exit[]
                else :
                    #print data
                    sys.stdout.write[data]
                    sys.stdout.write['[Me] ']; sys.stdout.flush[]     
            
            else :
                # user entered a message
                msg = sys.stdin.readline[]
                s.send[msg]
                sys.stdout.write['[Me] ']; sys.stdout.flush[] 

if __name__ == "__main__":

    sys.exit[chat_client[]]

Mã máy khách sẽ nghe tin nhắn đến từ máy chủ hoặc kiểm tra đầu vào của người dùng. Nếu người dùng nhập một tin nhắn thì hãy gửi nó đến máy chủ

Chúng tôi sử dụng chức năng select[] để xử lý cả hai tin nhắn. một từ stdin là đầu vào của người dùng và một từ máy chủ. Như chúng tôi nhớ lại, việc sử dụng phía máy chủ là chế độ không chặn, chúng tôi không làm gì với hàm select[] và chúng tôi sử dụng nó làm chế độ chặn. Vì vậy, chức năng select[] chặn [chờ] cho đến khi điều gì đó xảy ra. Nó sẽ chỉ trả về khi ổ cắm máy chủ nhận được tin nhắn hoặc người dùng nhập tin nhắn

Chủ Đề