国产人妻人伦精品_欧美一区二区三区图_亚洲欧洲久久_日韩美女av在线免费观看

合肥生活安徽新聞合肥交通合肥房產生活服務合肥教育合肥招聘合肥旅游文化藝術合肥美食合肥地圖合肥社保合肥醫院企業服務合肥法律

代寫INFO1112、代做Python語言程序
代寫INFO1112、代做Python語言程序

時間:2024-10-16  來源:合肥網hfw.cc  作者:hfw.cc 我要糾錯



INFO1112 - Assignment 2 - Tic-Tac-Toe
Tic-Tac-Toe, also known as Noughts and Crosses, is a simple yet engaging two-player game played on
a 3x3 board. The game is typically played by marking the board spaces with ‘X’ and ‘O’, with players
taking turns. The objective of the game is to be the ffrst to align three of your marks—either horizontally,
vertically, or diagonally. More about it on Wikipedia.
Since you have found it quite boring to play alone, you came up with the amazing idea of building a server
that allows people to connect and play with you online. The server has the following features:
• Users can log in
• Users can create game rooms
• Users can join existing game rooms either as players or as viewers
• Users can view players’ moves as they are played
The speciffcations are divided into 3 main sections, which dictate:
• The protocol used to communicate between the client and the server for running a game.
• Server-speciffc runtime details and implementation
• Client-speciffc runtime details and implementation
This assignment is due on Sunday, 20 Oct 2024 at 23:59, Sydney local time.
1 Getting Started
To assist you in the implementation of the assignment, the game logic and input handling for tic-tac-toe
has been implemented in 2 ffles in the scaffold: game.py, and tictactoe.py. Your task is to extend the
logic contained in these ffles, and create:
• a server program which is responsible for handling many games of tic-tac-toe being run simultaneously,
 and,
• a client program, which interacts with a game server (like the one you implement), and allows an
end-user to play tic-tac-toe over a network connection.
You are encouraged to run the function tic tac toe in game.py to play the game and understand how it
works. Of course, you are free to modify these ffles as much as you wish for your submission.
2 Sequence Diagrams
Throughout these speciffcations, we will be using simple sequence diagrams in order to visually depict how
protocol messages are sent back and forth between the client and the server. The shapes below outline the
sequence diagrams used in the assignment speciffcations:
• Messages from source to recipient are represented as a solid arrow with a solid arrow head. These
will be labelled with the protocol message being sent:
EXAMPLE:MESSAGE −−−−−−−−−−−−−−−−−−−−−−−−−−−−→
• Return messages from recipient to source are represented as a dashed arrow with a point arrowhead.
 This is for cases where a recipient is expected to send a message in response back to the source.
They will also be labelled with the protocol message being sent:
EXAMPLE:MESSAGE:RESPONSE
←−−−−−−−−−−−−−−−−−−−−
• Participants, which in this case, will either be a client or a server, can send and receive messages.
These will be depicted as rectangles with an associated lifeline – a dashed vertical line representing
the lifetime of the participant:
Participant
13 Protocol
In order to support playing the game over the network, your programs will need to implement a custom
application-layer protocol as described here in order to facilitate client and server interactions.
All communications will use TCP, and you should use sockets to communicate over the network. More
details about sockets are available from the documentation of Python’s socket module. A how-to guide
for getting started with using TCP sockets is available on Python’s website, and some material will be
included in the lab content to help explain how to create and interact with TCP sockets.
A couple of general notes about the protocol:
• Like many application-layer protocols (e.g. HTTP, SMTP), the protocol is text based, and speciffcally,
uses ASCII encoding for all data.
• When sending data over the network, you will need to ensure you encode data into bytes to send
it over a network socket, and when receiving data, you will need to ensure you decode the received
data to interpret this as a string.
– Hint 1: use the str.encode method to encode a string into bytes with a speciffed encoding.
– Hint 2: use the bytes.decode method to decode bytes to a string.
• You may assume that no message will ever exceed a buffer size of 8192 bytes.
• The majority of protocol messages require the user to be authenticated (after a LOGIN message)
in order for a client to be able to successfully interact with the server. If a category of messages
(one of the subheadings below) requires authentication, the subheading will have (authentication
required) written next to it to indicate this.
– Attempting to send a message from a client requiring authentication without being logged in
will result in a BADAUTH message being sent from the server to the client in response to the sent
message (see below).
3.1 Authentication-related Messages
3.1.1 LOGIN:<username>:<password>
This message is sent from the client to the server, and is used to authenticate a user account in order to
be able to play and/or watch games hosted by the server.
The client will send over the username of the user who is attempting to authenticate themselves, and a
plaintext password.
When the server receives this message, it will inspect the user database to check if the user with the given
<username> exists, and if so, checks that the sent <password> matches the password hash of the user
in the user database, which has been encrypted with the bcrypt algorithm (see Allowed Modules for
installing the bcrypt Python library on your local device).
• If the username exists in the user database, and the password provided matches the password hash
in the user database, the user will be considered to be successfully authenticated, meaning:
– the server should associate the client socket object of the user which sent the message with
the user account as actively authenticated, meaning the user has permission to interact with all
messages requiring authentication.
∗ multiple clients logging in to the same user account will not be assessed – you are free to
handle this how you see fft.
– the server should respond to the client with a LOGIN:ACKSTATUS:0 message, indicating a successful
 authentication.
– the client should print the message Welcome <username> to stdout after having received the
above message from the server.
• If the username cannot be found in the user database:
– the server should respond to the client with a LOGIN:ACKSTATUS:1 message.
– the client should print Error: User <username> not found message to stderr after having
received the message above
• If the username was found in the database, but the password sent did not match the password hash
in the database:
– the server should respond to the client with a LOGIN:ACKSTATUS:2 message.
2– the client should print Error: Wrong password for user <username> to stderr after having
 received the above message from the server.
• If a LOGIN message was sent with an invalid format, i.e. 0 or 1 arguments:
– the server should respond to the client with a LOGIN:ACKSTATUS:3 message.
– NOTE: Since your client program should be correct, it should never send an invalid LOGIN
message like this, and so there is no error message the client should print in this case. However,
this error message is included to help ensure robustness for the server handling such messages,
such as if you were to use a program such as netcat/nc to directly send messages to the server.
Sequence Diagram
LOGIN:<username>:<password>
LOGIN:ACKSTATUS:<status code>
Client Server
3.1.2 REGISTER:<username>:<password>
This message is sent from the client to the server, and is used to create a new user account in order to be
able to play and view games.
The client will send over the username and password of the user who is attempting to register themselves.
When the server receives this message, it will inspect the user database to ensure the user with the given
<username> exists does not exist, and will then perform an appropriate action described below:
• If the username does not exist in the user database, the user may be successfully created, meaning:
– the server should create a new user record in the user database, containing:
∗ the username of the new user.
∗ a password hash for the password for the new user account, hashed using the bcrypt
algorithm.
– once the user record is created, the server is required to immediately write to and update
the user database ffle with the new information for the user.
∗ you should either open and close the ffle for writing to do this, or altenatively, call the flush
method to immediately write the contents of the ffle to the disk – either is acceptable, as
long as no data is lost.
– the server should respond to the client with a REGISTER:ACKSTATUS:0 message, indicating a
successful user account creation.
– the client should print the message Successfully created user account <username> to
stdout after having received the above message from the server.
– NOTE: the user will not be logged in immediately after registration – the client needs to send
a separate LOGIN message to authenticate the user.
• If the username already exists in the user database:
– the server should respond to the client with a REGISTER:ACKSTATUS:1 message, indicating the
user already exists in the user database.
– the client should print the message Error: User <username> already exists to stderr
after having received the above message from the server.
• If a REGISTER message was sent with an invalid format, i.e. 0 or 1 arguments:
– the server should respond to the client with a REGISTER:ACKSTATUS:2 message.
– NOTE: Since your client program should be correct, it should never send an invalid REGISTER
message like this, and so there is no error message the client should print in this case. However,
this error message is included to help ensure robustness for the server handling such messages,
such as if you were to use a program such as netcat/nc to directly send messages to the server.
Sequence Diagram
3.1.3 BADAUTH
This is a special message which will be sent from the server to the client in response to any protocol
message which requires authentication to perform – so make sure you check for this message when sending
3REGISTER:<username>:<password>
REGISTER:ACKSTATUS:<status code>
Client Server
an authenticated message from the client!
When a client receives this message, it should output Error: You must be logged in to perform
this action to stderr.
Sequence Diagram
<any message requiring authentication>
BADAUTH
Client Server
3.2 Room-related Messages (authentication required)
3.2.1 ROOMLIST:<mode>
This message is sent from the client to the server, and is used to list rooms that are available to be joined
in the speciffed <mode>.
<mode> may be either:
• PLAYER – indicating rooms available to join as a player (and be able to play the game against an
opponent).
• VIEWER – indicating rooms available to join as a viewer (and be able to watch a given game).
When the server receives this message, if <mode> is formatted correctly, the server will respond with the
message ROOMLIST:ACKSTATUS:0:<room list>, where <room list> is a list of comma-separated room
names that are available. For instance, if the available room names are:
• Room 1
• epic room 2
• another epic room
<room list> will be formatted as Room 1,epic room 2,another epic room, and thus, the acknowledgement
 message sent from the server back to the client in full will be:
ROOMLIST:ACKSTATUS:0:Room 1,epic room 2,another epic room
Upon receiving the server feedback, the client will output ”Room available to join as <mode>: <roomlist
received>” which in the example will be ”Room available to join as <mode>: Room 1,epic room
2,another epic room”
Error handling
• If a ROOMLIST message was sent with an invalid format, such as having more/less than 1 argument,
or <mode> not being PLAYER or VIEWER:
– the server should respond to the client with a ROOMLIST:ACKSTATUS:1 message.
– the client should rasie the error to stderr”Error: Please input a valid mode.”
Sequence Diagram
ROOMLIST:<mode>
ROOMLIST:ACKSTATUS:<status code>[:<room list...>]
Client Server
43.2.2 CREATE:<room name>
This message is sent from the client to the server, and is used to create a room with a speciffed <room
name>.
Room names must meet the following criteria:
• they may only contain alphanumeric characters (a-z, A-Z, 0-9), dashes, spaces, and underscores.
• they must be a maximum of 20 characters in length.
which is validated on the server side.
The server also only allows a maximum of 256 rooms to be created. Once a game is complete, the room
is deleted.
When the server receives this message, it will perform an appropriate action described below:
• If the room named <room name> does not already exist, and the <room name> is valid (from the
above criteria):
– the user that created the room will automatically join the room
– the server should respond to the client with a CREATE:ACKSTATUS:0 message.
– the client should print the message Successfully created room <room name> to stdout
after having received the above message from the server.
– And the client end will wait until there’s another player joined the room. During
the wait, the client isn’t supposed to do anything else other than printing ”Waiting for other
player...”.
∗ Once the client end of the ffrst player in teh room received the BEGIN messsage mentioned
below, the game will start.
• If the room name character is invalid,
– the server should respond to the client with a CREATE:ACKSTATUS:1 message.
– the client should print the message Error: Room <room name> is invalid to stderr after
having received the above message from the server.
• If the <room name> received already refers to a created room:
– the server should respond to the client with a CREATE:ACKSTATUS:2 message.
– the client should print the message Error: Room <room name> already exists to stderr
after having received the above message from the server.
• If there are already 256 rooms created in the server (meaning no further rooms can be created):
– the server should respond to the client with a CREATE:ACKSTATUS:3 message.
– the client should print the message Error: Server already contains a maximum of 256
rooms to stderr after having received the above message from the server.
• If a CREATE message was sent with an invalid format, i.e. 0 or 1 arguments:
– the server should respond to the client with a CREATE:ACKSTATUS:4 message.
– NOTE: Since your client program should be correct, it should never send an invalid CREATE
message like this, and so there is no error message the client should print in this case. However,
this error message is included to help ensure robustness for the server handling such messages,
such as if you were to use a program such as netcat/nc to directly send messages to the server.
Sequence Diagram
CREATE:<room name>
CREATE:ACKSTATUS:<status code>
Client Server
53.2.3 JOIN:<room name>:<mode>
This message is sent from the client to the server, and is used to join a room with a specified <room name>
in the specified <mode>.
<mode> may be either:
• PLAYER – indicating rooms available to join as a player (and be able to play the game against an
opponent).
– NOTE: There may only be 2 players in 1 given room. It is invalid for any further players to
try to join a room as a player in this case.
• VIEWER – indicating rooms available to join as a viewer (and be able to watch a given game).
When the server receives this message, it will perform an appropriate action described below:
• If the room named <room name> exists, and the <mode> provided is a valid mode, and the user can
successfully join the room (from the above criteria):
– the server should add the user into the room in the mode specified by the message sent by the
client.
– the server should respond to the client with a JOIN:ACKSTATUS:0 message.
– the client should print the message Successfully joined room <room name> as a <specified
mode> to stdout after having received the above message from the server, where <specified
mode> is either player or viewer, based on what was sent.
• If there is no room named <room name> in the server:
– the server should respond to the client with a JOIN:ACKSTATUS:1 message.
– the client should print the message Error: No room named <room name> to sderr after having
received the above message from the server.
• If the player is attempting to join <room name> as a PLAYER, but the room is already full (has 2
players):
– the server should respond to the client with a JOIN:ACKSTATUS:2 message.
– the client should print the message Error: The room <room name> already has 2 players
to stderr after having received the above message from the server.
• If a JOIN message was sent with an invalid format, such as having more/less than 2 arguments, or
<mode> not being PLAYER or VIEWER:
– the server should respond to the client with a JOIN:ACKSTATUS:3 message.
– NOTE: Since your client program should be correct, it should never send an invalid JOIN
message like this, and so there is no error message the client should print in this case. However,
this error message is included to help ensure robustness for the server handling such messages,
such as if you were to use a program such as netcat/nc to directly send messages to the server.
Sequence Diagram
JOIN:<room name>:<mode>
JOIN:ACKSTATUS:<status code>
Client Server
3.3 Game-related messages (authentication required)
These messages describe interactions between an active game of tic-tac-toe between 2 players.
For any messages which a client sends to the server, the client is required to be authenticated, otherwise,
a BADAUTH message is sent in response by the server.
For these messages, both client and server programs may assume that messages will always be sent and
received in a valid format, hence there is no need to check that messages constructed are of a valid format
in for the below messages.
If, however, a client sends a message specified in this category, but they are not currently in a room (as
either a player or a viewer), the server should respond with a NOROOM message (see below).
63.3.1 BEGIN:<player 1>:<player 2>
This message is sent from the server to a client, used to inform clients about the players which will be
versing each other when commencing a game of tic-tac-toe.
<player 1> is the username of the player who places the first marker (an ’X’), while <player 2> is the
username of the player who places the second marker (an ’‘’O’).
When a second player joins a room, the server will send this message to all players and viewers in the
current room, informing them that a game is to begin:
• the client who is logged in as player <player 1> will be prompted to begin the game and place their
first marker.
• the client who is logged in as player <player 2> will be prompted to wait until <player 1> has
placed their first marker (which means that they need to wait until a BOARDSTATUS message has been
sent by the server (see below)).
• any room member’s client end should output the message ”match between <player 1> and <player
2> will commence, it is currently <player 1>’s turn.’”
This message does not require the client to send anything in response.
Sequence Diagram
BEGIN:<player 1>:<player 2>
Client Server
3.3.2 INPROGRESS:<current turn player>:<opposing player>
This message is sent from the server to a client who joins as a viewer to an in-progress game, informing
them:
• the username of the player who’s turn it currently is (<current turn player>).
• the username of the opposing player who is awaiting their turn (<opposing player>).
When the viewing client receives this message, it should output the message ”Match between <current
turn player> and <opposing player> is currently in progress, it is <current turn player>’s turn”
This message does not require the client to send anything in response and players’ client ends are not
supposed to receive this message.
Sequence Diagram
INPROGRESS:<player 1>:<player 2>
Client Server
3.3.3 BOARDSTATUS:<board status>
This message is sent from the server to a client to inform them of the current status of the game board
after a move has been made by a player.
Every player and viewer in a room must receive this message after a move has been made.
<board status> explainer
<board status> is a 9-character text string which represents the current state of the 3x3 tic-tac-toe board.
There are 3 characters used to represent a space on the tic-tac-toe board:
• 0 – empty space
• 1 – ’X’ marker
7• 2 – ’O’ marker
The string is essentially a 1D mapping of the 2D array for tic-tac-toe: i.e. each space in the tic-tac-toe
board numbered like so:
1 2 3
4 5 6
7 8 9
is mapped to the <board status> string 123456789.
For instance, a board of the current status:
X O
X
O
would have <board status> equal to 012010020.
Client actions
Any time a client receives this message, they should print the board’s current status to stdout.
Depending on whether the client in the game is a player or viewer, other specific actions will be performed:
• if the client is a player, and:
– has just placed their own marker (having just sent PLACE:<x>:<y> to the server), the client will
recognise that it is the opposing player’s turn (who’s username is known from the BEGIN message
sent when the game has started), and will output that ”It is the opposing player’s turn”,
and wait for the opposing player to complete their turn.
– has been waiting for an opposing player – if this message is received by the player, it means
that the opposing player has placed their marker, and hence, the client should output ”‘It is
the current player’s turn’”, and ask the user to input the x-y coordinates of the marker they
wish to place.
• if the client is a viewer, after having printed the board to stdout, the client should print that it
is the next corresponding player’s turn (the client will have the names of all players from either a
BEGIN or INPROGRESS message sent prior).
This message does not require the client to send anything in response.
Sequence Diagram
BOARDSTATUS:<board status>
Client Server
3.3.4 PLACE:<x>:<y>
This message is sent from the client to the server, and is used by a player to place a marker on the board
when it is the player’s current turn.
<x> and <y> refer to the coordinates on where the marker should be placed on the game board, using
0-based indexing for the spot.
The server makes the assumption that the client sending this message has already validated that <x> and
<y> is valid on the client side (i.e. valid coordinates, not currently occupied, etc.), and that the PLACE
message will always contain 2 arguments, and hence will simply process the request as is without needing
to do any error handling. (As a rationale for this, imagine that this protocol will only ever by used by our
own program implementations)
Once a client has sent a PLACE message to the server, the server will place the marker corresponding to the
player appropriately, and send either a BOARDSTATUS message informing the player of the current board’s
status as an acknowledgement, or a GAMEEND message (see below), indicating the game has finished.
8Sequence Diagram
PLACE:<x>:<y>
<return message>
Client Server
3.3.5 FORFEIT
This message is sent from the client to the server, and is used by a player when it is their current turn to
indicate that they wish to forfeit the current game.
Once this message is sent, the game will end, and the server will send a GAMEEND message with a <status
code> of 2 (indicating a forfeitted win) for the opposing player (see below) to all players and viewers.
Sequence Diagram
FORFEIT
GAMEEND:<board status>:2:<opposing player username>
Client Server
3.3.6 GAMEEND:<board status>:<status code>[:<optional arg>]
This message is sent from the server to a client to inform them that the game of tic-tac-toe in the current
room has concluded.
<board status> represents the status code of the board at the time of the game ending, in the same
format as described in the BOARDSTATUS message (see above).
The <status code> dictates whether the game has been won by a given player (which would be provided
as an <optional arg>, or whether the game has ended in a draw):
• a <status code> of 0 indicates a player has won the game. In this case, the GAMEEND message will
include a 3rd argument, which is the username of the winner of the game:
GAMEEND:<board status>:0:<winner username>
• a <status code> of 1, indicating the game has ended in a draw. No additional arguments will be
provided:
GAMEEND:<board status>:1
• a <status code> of 2, indicating that a player has forfeited the game. This may result in 3 circumstances:

a player has purposely sent a FORFEIT message (see above) to the server when it is their turn.
– a player has disconnected while a game is in progress. In this case, the server will assume that
the player which has disconnected has implicitly forfeitted the game.
– a player’s client end encountered EOF while in the middle of the game (they should disconnect
from the server as well).
In this case, the GAMEEND message will include a 3rd argument, which is the username of the (default)
winner of the game:
GAMEEND:<board status>:2:<winner username>
After sending this message, the server will delete the room the game has been occurring in, and allow users
to create/join rooms again.
When clients receives this message, they should print the status of the game’s board, and respond according
to their mode in the room they are currently in:
• if they are a player, and the <status code> was 0 (indicating a win):
9– their username matches the <winner username>: a message should be printed to stdout,
congratulating the user that they have won the game: ”Congratulations, you won!”
– their username does not match the <winner username>: a message should be printed to stdout,
informing the user has lost the game, and wishing them better luck next time: ”Sorry you
lost. Good luck next time.”
• if they are a viewer, and the <status code> was 0 (indicating a win), a message should be printed
indicating that ”<winner username> has won this game”.
• if they are either a player or a viewer, and the <status code> was 1 (indicating a draw), each client
should print a message to stdout informing them that ”Game ended in a draw”.
• if they are either a player or a viewer, and the <status code> was 2 (indicating a player has
forfeitted), each client (if they are still running) should print a message to stdout informing them
”<winner username> won due to the opposing player forfeiting”.
This message does not require the client to send anything in response.
Sequence Diagram
GAMEEND:<board status>:<status code>[:<optional arg>]
Client Server
3.3.7 NOROOM
This message is sent from the server to a client, in the case that the client which sent a game-related
message (as those described above that can be sent from a client to the server) is, for whatever reason,
not currently inside a room (as a player or a viewer).
Sequence Diagram
<any game-related message when not in a room>
NOROOM
Client Server
3.4 Example Game (after joining room): Sequence Diagram
To help illustrate an example of a complete game (from a client being a player’s perspective), a sequence
diagram is included below which helps to illustrate the communications which would occur between a
client and server from the beginning until the end of a game. In this case, the player’s username is alice.
BEGIN:alice:bob
PLACE:1:1
BOARDSTATUS:000010000
BOARDSTATUS:200010000
PLACE:0:2
BOARDSTATUS:200010100
BOARDSTATUS:220010100
PLACE:2:0
GAMEEND:221010100:0:alice
Client Server
• As you can see in this diagram, once the game is started, the server will broadcast 2 players to
everyone in the room. In this case, both viewers and players will know who’s in the game as players.
As mentioned before, the message send from server to client at the start indicates it’s Alice’s turn.
10• The server will wait for Alice to place a piece. If this time Bob is trying to place a piece, we we
mentioend before, Bob’s client is supposed to raise ”It is the opposing player’s turn”.
• After Alice has placed a piece, the server will broadcast the BOARDSTATUS to all of the clients in the
room, which is both players and viewer as mentioned before in client action under BOARDSTATUS
protocol.
– Any time a client receives BORDSTATUS message, they should print the board’s current status
to stdout. Depending on whether the client in the game is a player or viewer, other specific
actions will be performed:
∗ if the client is a player, and:
· has just placed their own marker (having just sent PLACE:<x>:<y> to the server), the
client will recognise that it is the opposing player’s turn (who’s username is known from
the BEGIN message sent when the game has started), and will output that ”It is the
opposing player’s turn”, and wait for the opposing player to complete their turn.
· has been waiting for an opposing player – if this message is received by the player, it
means that the opposing player has placed their marker, and hence, the client should
output ”‘It is the current player’s turn’”, and ask the user to input the x-y coordinates
of the marker they wish to place.
∗ if the client is a viewer, after having printed the board to stdout, the client should print
that it is the next corresponding player’s turn (the client will have the names of all players
from either a BEGIN or INPROGRESS message sent prior).
• And after this, it will be Bob’s turn.
• The rest of the game will follow such behaviour until one of them wins or they reached a draw. And
the client ends are suppposed to print the messages as specified in GAMEEND protocol.
4 Server Program Details
Your server is open to different configurations and is held locally. It needs configurations for which port to
listen to, which database it’s reading from and manage all of the concurrent conenctions. All of the mssages
received from client and server sends are treated as strings. To ensure asynchronous communication, the
server should utilise non-blocking IO and/or processes. Some example methodologies to implement this
include:
• the high-level selectors module, which wraps the lower-level select module to provide an easier
interface for dealing with non-blocking I/O. An example of the module being used for non-blocking
I/O is available in the docs page here.
• the lower-level select module, which allows you to handle sockets only when they have data ready
to read from. An example usage of using select.select for this purpose is included below:
def server_loop(server_sock: socket.socket) -> None:
# Assuming `server_sock` has already been set up to be non-blocking
read_socks = {server_sock}
# Do any other necessary setup
...
# Infinite loop for server (for demonstration)
with server_sock:
while True:
select_read_socks, _, select_except_socks = select.select(
read_socks,
(), # empty tuple
(),
)
for sock in select_read_socks:
11if sock is server_sock:
# New client available
client_sock, client_addr = sock.accept()
client_sock.setblocking(False)
read_socks.add(client_sock)
else:
# `sock` is client socket
client_msg = sock.recv(8192)
if not client_msg:
# Empty message (0 bytes) indicates disconnection
read_socks.remove(sock)
sock.close()
continue
# Do something with the client message...
...
for sock in select_except_socks:
# N.B: this is unlikely to actually ever contain any sockets, so
# you can probably ignore it, although it is included here for
# completeness
read_socks.remove(sock)
sock.close()
• use threading or multiprocessing (which has a near-identical API, just uses processes rather than
threads) to spawn a thread or child process for each client that connects, and use appropriate tools
to share data between threads/child processes. Keep in mind that you should be aware of caveats
that may occur in this, such as race conditions, and use features such as synchronisation primitives
to protect shared data, such as reading from/writing to the user database. A simple example of
using threading or multiprocessing is available in this Stack Overflow thread.
• use os.fork to create a child process for each client that connects. Be mindful to ensure your
child processes don’t overwrite data for the user database if this method is used – you may need
to implement some form of synchronisation. The above methods may be easier to ensure this when
compared to this method.
As you want your mates to play the game with you, any servers that can only serve one
single client will not be accepted, and will result in a deduction of 50% of the total marks
for this assignment.
4.1 Launching
The server should be launched as follows
python3 server.py <server config path>
where <server config path> is a path to a configuration file used to configure the server (see below for
more details).
4.1.1 Error cases
• If there is more or less than 1 argument passed to the server program, the server will raise the error:
”Error: Expecting 1 argument: <server config path>.” and terminate itself.
4.2 Configuration Files
The server program requires 2 configuration files, formatted as JSON, in order to support the server’s
operations.
124.2.1 Server configuration
This configuration file is passed as the sole command-line argument to the server, and will detail:
• the port the server to run on (given by the key port). Note that a port is valid only if it is an integer,
and is in the range 1024-65535.
• The path to the database for user accounts (given by the key userDatabase). This may be both a
relative path, or an absolute path.
– If a relative path is provided, you should interpret the path as being relative to the current
working directory from where the server is running from (thankfully, you should not need to
worry about having any additional logic to handle this).
– Note that this path may include the ~ (tilde) to refer to the home directory – make sure you
are able to expand this as required.
An example of the expected format of this file is included below:
{
"port": 6502,
"userDatabase": "~/ticTacToeUsers.json"
}
Error and edge cases
• If the provided path to the server config does not exist, the server will raise the error ”Error:
<server config path> doesn’t exist.” and terminate itself.
• If the server config is not in a valid JSON format, the server will raise the error ”Error: <server
config path> is not in a valid JSON format.” and terminate itself.
• If the port or userDatabase keys are missing from the server config file, the server will raise the
error ”Error: <server config path> missing key(s): <missing key list>” and terminate
itself.
• If the port is out of the designed range, the server will raise the error ”Error: port number out
of range” and terminate itself.
• <missing key list> is a comma-separated list of the missing required keys, sorted in alphabetical
order.
For instance, if only port was missing, the error message would be:
Error: <server config path> missing key(s): port
but if both port and userDatabase was missing, the error message would be:
Error: <server config path> missing key(s): port, userDatabase
• If there are any extra, unknown keys, don’t raise any errors: simply ignore them.
4.2.2 User database configuration
Once the server read the server configuration file, it will use the user database path to find the user
database file. The user database is the place to store all of the registered users for the application. It is a
JSON file that stores users as objects in the folowing format:
[
 {
"username": "john_doe",
"password": "$2a$12$E9xL6KFnZnyOaHjkl2qS5uX1cdTZZa.tUOpjdWxglMvS8bkcVEzCu"
},
{
"username": "jane_smith",
"password": "$2a$12$R7UVn/.J01PQBuEdCVBxeOQULa4BWxolZiG/tLcl2eXEz69GvV4ua"
}
]
13As you noticed in the database sample, the password is stored as a hash generated by the bcrypt algorithm.
More info about this is discussed in the LOGIN and REGISTER messages described in the Protocol section
above.
Edge cases
• If the user database path cannot be found, the server will raise the error ”Error: <user database
path> doesn’t exist.” and terminate itself.
• If the user database isn’t in a valid JSON format, the server will raise the error ”Error: <user
database path> is not in a valid JSON format.” and terminate itself.
• If, when the server is launched:
– the user database is not a JSON array (the json module will load this as a Python list),
the server will raise the error ”Error: <user database path> is not a JSON array.” and
terminate itself.
– a user record is not in a valid format (only containing "username" and "password" keys), the
server will raise the error ”Error: <user database path> contains invalid user record
formats.” and terminate itself.
NOTE: You can assume that after the server program has been launched, no other program will
modify the user database – this is why this only needs to be checked when upon launch.
4.3 Miscellaneous Edge and Error Cases
4.3.1 Player dropping out
Although any connected player client should always finish the game, there is always the possibility that one
player drop out of the game without explicitly forfeiting (for instance, losing a connection to the server).
If one of the players drop out of the game for whatever reason, the server should treat the disconnected
player as having implicitly forfeitting the game, and send a GAMEEND message with a <status code> of 2 to
the other connected player and all connected viewers. Refer to the GAMEEND protocol message subheading
under the Protocols section for further details.
4.3.2 Viewer sending a message to the server
Clients which are viewers are not expected to send any messages to the server, as they are only viewing
a game currently in progress. However, if, for whatever reason, a viewer client did send a message to the
server, the server should simply ignore the message sent by the viewer, and perform no further action.
5 Client Program Details
client.py is a key part to help you connect to the server, and be able to play online with your friends!
5.1 Launching
The client is expected to be launched in the following format:
python3 client.py <server address> <port>
where <server address> is the IPv4 address of the server you wish to connect to, and <port> is the port
the server is running on.
Hint: To test your server running on your local machine, use your local machine’s address (typically you
can just write localhost, or 127.0.0.1).
145.1.1 Error cases
• If there is more or less than 2 arguments passed to the client program, the client will raise the error:
”Error: Expecting 2 arguments: <server address> <port>” and terminate itself.
• If the client cannot connect to to the server at the specified <server address> and <port>, the client
should output ”Error: cannot connect to server at <server address> and <port>.”, and
terminate itself.
5.2 Reconstruction of User Input
To make the server user friendly, you are not expecting the user to put in the exact protocol message.
Instead, you are suposed to ask the user to put in the information in a user-friendly way and reconstruct
it into the protocol message and send to the server. The client will run in an infinite loop, taking input
from the user until EOF or they input QUIT.
5.2.1 Outside of Game
When a user is not currently playing/viewing a game inside of a room, the client will ask the user to enter
the following commands to perform an action:
LOGIN
Users will type in ”LOGIN” in the client end to indicate they want to login.
Your client will ask the user to input the username first:
Enter username:
And then your client will ask the user to input the password:
Enter password:
After receiving the user input, your client will reconstruct it to the protocol message: LOGIN:<username>:<password>,
send this to the server, and handle the protocol message the server sends in response accordingly (see above
for information on handling LOGIN:<username>:<password> in the Protocol section).
NOTE: Your client will not raise any errors before reconstructing the protocol message,
meaning it will not check the validity of individual user’s username and password input, but
instead, it will simply send the protocol message LOGIN:<username>:<password> to the server.
REGISTER
Users will type in ”REGISTER” in the client end to indicate they want to login.
Your client will ask the user to input the username first:
Enter username:
And then your client will ask the user to input the password:
Enter password:
After receiving the user input, your client will reconstruct it to the protocol message: REGISTER:<username>:<password>,
send this to the server, and handle the protocol message the server sends in response accordingly (see above
for information on handling REGISTER:<username>:<password> in the Protocol section).
NOTE: Your client will not raise any errors before reconstructing the protocol message,
meaning it will not check the validity of individual user’s username and password input,
but instead, it will simply send the protocol message REGISTER:<username>:<password> to the
server.
ROOMLIST
User will type in ”ROOMLIST” in the client to indicate they want to have a room list. This time, your
client end is supposed to ask the user the following question:
15Do you want to have a room list as player or viewer? (Player/Viewer)
(note the input for this above question is treated as case-insensitive).
The client will reconstruct the message first to ”ROOMLIST:<userinput>” and send it to the server without
checking the user input.
Edge/error cases
• If the user enters something other than Player or Viewer (case-insensitive), the client will prompt
the user to try again, with the message Unknown input. being printed in a separate line, before
re-prompting the user.
CREATE
User will type in ”CREATE” in the client to indicate they want to creat a room. This time, your client is
supposed to ask the user the follwing question:
Enter room name you want to create:
The client will reconstruct the message first to ”CREATE:<userinput>” and send it to the server without
checking the user input. See the CREATE:<room> subheading under the Protocol section for details on
how to handle server responses to this protocol message.
JOIN
User will type in ”JOIN” in the client to indicate they want to join a room. This time, your client is
supposed to ask the user the follwing question:
Enter room name you want to join:
And then the server will ask the user the following question:
You wish to join the room as: (Player/Viewer)
(note the input for this above question is treated as case-insensitive).
The client will reconstruct the message first to ”JOIN:<userinput for room name>:<userinput for
mode>” and send it to the server without checking the userinput.
Edge/error cases
• If the user enters something other than Player or Viewer (case-insensitive) for the second question,
the client will prompt the user to try again, with the message Unknown input. being printed in a
separate line, before re-prompting the user.
5.2.2 In-game (Player) Commands
When inside of a game as a player, and it is currently the user’s turn to perform some action on the game
board, the user may enter the following commands:
PLACE
When a user enters this command, they should be further prompted to enter the coordinates for where
they would like to place their marker: first the column, then the row (which will be identical to how the
scaffold tic-tac-toe game is presented).
As tic-tac-toe uses a 3x3 board, coordinates must be in the range 0-2 for both the column and row.
Validation of the move will be performed by the client program, prior to informing the server of the move
the player has made. If any of the below criteria occur, the move should not be sent to the server, and
the client should re-request for valid coordinates to be enterred:
• If either the column or row is not an integer or is not within the range 0-2, the client program should
print the error (Column/Row) values must be an integer between 0 and 2, and re-request the
user the user to re-enter the column/row respectively.
16• If the player tried to place the piece on the coordinate that’s already occupied, the client will raise the
error ”(<x>, <y>) is occupied by <marker character>.”, and will re-request the user to enter
another set of coordinates.
If the coordinates enterred by the user are valid and a spot may be placed there, the client will send a
PLACE:<x>:<y> protocol message to the server, indicating the player’s move.
FORFEIT
This command may be enterred by the player to forfeit the game (and thus lose). When enterred, this will
send a FORFEIT protocol message to the server. The client, however, should still remain in the room until
the server sends a GAMEEND message in response.
5.3 Miscellaneous Error Cases
• If, while running, the client receives any data from the server which is not a valid protocol message
specified above, the client should output ”Unknown message received from server. Exiting...”,
and terminate itself.
• If an unknown command is enterred, both outside or inside the game, the client should output
Unknown command: <unknown command name>, and re-request the user to enter a command again.
6 Allowed Modules
The following Python standard and third-party library modules are permitted to be used in your submission
• abc
• bcrypt
• collections.abc
• dataclasses
• enum
• json
• mmap
• multiprocessing
• os
• os.path
• pathlib
• re
• select
• selectors
• signal
• socket
• sys
• threading
• typing
• queue
NOTE: bcrypt is available on Ed, but when working on the assignment on your local machine, you will
need to install this, as it is a third-party library. Installation instructions are below:
• On Ubuntu/Debian-based systems, run:
sudo apt install python3-bcrypt
• On Fedora-based systems, run:
sudo dnf install python3-bcrypt
• On Arch Linux-based systems, run:
sudo pacman -S python-bcrypt
17• On all other systems (including macOS) (or if there are any issues with the above commands for
your specific Linux distro), run one of the two commands:
pip install --user bcrypt
pip3 install --user bcrypt
Any other modules which are not on this above list may not be used in your assignment, and will
result in a mark deduction (20% of A2 max grade, or 4 marks) if they are used.
This list, however, may be expanded in future. If you would like to use a certain Python module, please
ask on Ed, and staff will be happy to review your request, and if appropriate, update the list of allowed
modules. A pinned post will be created which will track any updates to the list of allowed modules.
6.1 Strictly Forbidden Functions
In addition to the above restrictions, the following functions are strictly fobidden, and carry a more severe
penalty for use.. Using these functions will also result in a mark deduction of 40% of your A2 max grade
(8 marks).
• import function to improve a module - please use the standard import keyword to import modules
and/or functions.
7 Test Report
As part of your submission, you are expected to test your code on your own. Due to the difficulty of I/O
tests for this server, you are supposed to generate a test report. The word limit for the report is 500 words.
The report is supposed to contain the following contents:
• A simple list of the features you’ve tested.
• A screenshot of the command you input and the corresponding response from the server for each
testing scenario.
• (If you didn’t implement some specific function, please describe how you will test it and what’s the
output supposed to be).
8 Marking Breakdown
The mark breakdow for this assessment is as follows:
• Automated test cases (17 marks) - marks from automated testcases from Ed, which includes public,
hidden and provate testcases. (Different cases will have different weightings attached to them, visible
on Ed). Private test cases may be run after the due date.
• Testing (4 marks)
• Code style (4 marks)
– Automated code styling checing with Pylint (2 marks) - feel free to fun pylint on your code to
check your dcode style yourself.
∗ Score >= 7.5/10 = 2/2 marks
∗ 5.5/10 <= score < 7.5/10 = 1.5/2 marks
∗ 2.5/10 <= score < 5.5/10 = 1/2 marks
∗ 1/10 <= score < 2.5/10 = 0.5/2 marks
∗ score < 1 = 0/2 marks
– Manual code style checking (2 marks)
∗ As part of manual code style checking, you should ensure that your Git repository is clean,
and there are no unused files in your submission that do not relate to your code (e.g. binary
files like pycache /, unused Python files, etc.). You will need to ensure this is the case
to achieve full marks for this section. You are encouraged to use or take advantage of the
.gitignore in the assignment scaffold for this purpose.
189 Friendly Note and Important Dates
This assignment is due on Sunday, 20 Oct 2024 at 23:59, Sydney local time.
Sometimes we find typos or other errors in specifications. Sometimes the specification could be clearer.
Students and tutors often make great suggestions for improving the specification. Therefore, this assignment
specification may be clarified up to Week 10, Sunday, 13th October. No major changes will be made.
Revised versions will be clearly marked, and the changelog updated both on the assignment specs, and
made visible by a pinned post on Ed.
You are encouraged to apply for special consideration and arrangements if any difficulty comes up which
may impact your submission for the assignment on time.
Please make sure to also reach out to staff for any questions on the specs!
A friendly reminder that per the unit outline, late submissions are not accepted and result in a
mark of 0 being awarded for the assignment.
10 Warning
Any attempts to deceive the automatic marking system will result severe deductions to your assignment
mark. This includes hardcoding to try and match test cases.
Negative marks can be assigned if your code is unnecessarily or deliberately obfuscated.
All documentation in your submission, including comments, code variables, and so on, must be written
in English. If not, penalties will apply. A deduction of 1 mark per line of non-English code will
apply, up to a maximum deduction of 5/20 marks for the assignment.
11 Academic Declaration
By submitting this assignment, you declare the following: I declare that I have read and understood the
University of Sydney Student Plagiarism: Coursework Policy and Procedure, and except where specifically
acknowledged, the work contained in this assignment/project is my own work, and has not been copied
from other sources or been previously submitted for award or assessment. I understand that failure to
comply with the Student Plagiarism: Coursework Policy and Procedure can lead to severe penalties as
outlined under Chapter 8 of the University of Sydney By-Law 1999 (as amended). These penalties may
be imposed in cases where any significant portion of my submitted work has been copied without proper
acknowledgement from other sources, including published works, the Internet, existing programs, the work
of other students, or work previously submitted for other awards or assessments. I realise that I may be
asked to identify those portions of the work contributed by me and required to demonstrate my knowledge
of the relevant material by answering oral questions or by undertaking supplementary work, either written
or in the laboratory, in order to arrive at the final assessment mark. I acknowledge that the School of
Computer Science, in assessing this assignment, may reproduce it entirely, may provide a copy to another
member of faculty, and/or communicate a copy of this assignment to a plagiarism checking service or
in-house computer program, and that a copy of the assignment may be maintained by the service or the
School of Computer Science for the purpose of future plagiarism checking.
12 Changelog
Any clarifications to the specs will be noted here. 24/09/2024
• ROOMLIST:<mode> added client interpretation on the server feedback.
• Added CREATE:ACKSTATUS:1 for invalid room name 26/09/2024
• ROOMLIST:<mode> typo fixed joint -¿ join
• Change in client end for ROOMLIST:<mode>: the user input should be checked in client end and raise
error. 30/09/2024
19• United the logic when print to stderr or stdout. When it’s not an error message, it will be printed
out to stdout. WHen it’s a error message, it wil be printed to stderr. 1/10/2024
• Add the client behaviour when there’s only 1 player in the room. The client end will stuck and print
out the waiting message. When another player join and the client end received the BEGIN message,
the waiting ends. 3/10/2024
• Clarification: Once the user created the room, the user will joint it automatically.
• Fixed the inconsistency to raise the client error in ROOMLIST
• Clarified INPROGRESS’s player 1 and 2’s order issue.
• Clarified the behaviour if port number out of range when starting server
20

請加QQ:99515681  郵箱:99515681@qq.com   WX:codinghelp





 

掃一掃在手機打開當前頁
  • 上一篇:FIT2102代做、代寫Java/Python設計程序
  • 下一篇:RBE104TC代做、C/C++編程設計代寫
  • 無相關信息
    合肥生活資訊

    合肥圖文信息
    流體仿真外包多少錢_專業CFD分析代做_友商科技CAE仿真
    流體仿真外包多少錢_專業CFD分析代做_友商科
    CAE仿真分析代做公司 CFD流體仿真服務 管路流場仿真外包
    CAE仿真分析代做公司 CFD流體仿真服務 管路
    流體CFD仿真分析_代做咨詢服務_Fluent 仿真技術服務
    流體CFD仿真分析_代做咨詢服務_Fluent 仿真
    結構仿真分析服務_CAE代做咨詢外包_剛強度疲勞振動
    結構仿真分析服務_CAE代做咨詢外包_剛強度疲
    流體cfd仿真分析服務 7類仿真分析代做服務40個行業
    流體cfd仿真分析服務 7類仿真分析代做服務4
    超全面的拼多多電商運營技巧,多多開團助手,多多出評軟件徽y1698861
    超全面的拼多多電商運營技巧,多多開團助手
    CAE有限元仿真分析團隊,2026仿真代做咨詢服務平臺
    CAE有限元仿真分析團隊,2026仿真代做咨詢服
    釘釘簽到打卡位置修改神器,2026怎么修改定位在范圍內
    釘釘簽到打卡位置修改神器,2026怎么修改定
  • 短信驗證碼 寵物飼養 十大衛浴品牌排行 suno 豆包網頁版入口 wps 目錄網 排行網

    關于我們 | 打賞支持 | 廣告服務 | 聯系我們 | 網站地圖 | 免責聲明 | 幫助中心 | 友情鏈接 |

    Copyright © 2025 hfw.cc Inc. All Rights Reserved. 合肥網 版權所有
    ICP備06013414號-3 公安備 42010502001045

    国产人妻人伦精品_欧美一区二区三区图_亚洲欧洲久久_日韩美女av在线免费观看
    亚洲欧美影院| 狠狠色噜噜狠狠色综合久| 日韩高清专区| 91久久偷偷做嫩草影院| 超碰日本道色综合久久综合| 欧美亚洲国产日本| 日韩一区二区久久久| 天天爱天天做天天操| 国产乱人伦精品一区二区| 国产精品流白浆视频| 欧美激情国产精品日韩| 精品国产一区久久久| 日韩视频免费播放| 久久青草精品视频免费观看| 亚洲一区二区三区四区中文| 成人9ⅰ免费影视网站| 中文字幕在线中文字幕日亚韩一区| 国产一区二区三区播放| 国产精品网站入口| 欧美激情第一页在线观看| 久久精品视频在线观看| 欧美日韩精品不卡| 国产精品人人妻人人爽人人牛| 日本精品一区二区三区视频| 久久偷窥视频| 日韩精品一区中文字幕| 色老头一区二区三区| 欧美怡红院视频一区二区三区| 精品国产欧美一区二区五十路 | 日韩视频免费观看| 欧美在线视频二区| 国产精品久久久久久久久借妻 | 色欲av无码一区二区人妻| 久久青青草原一区二区| 日本a在线天堂| 久久精品在线视频| 国产又黄又大又粗视频| 一级做a爰片久久| 国产成人jvid在线播放| 男女猛烈激情xx00免费视频| 欧美猛交免费看| 91精品国产综合久久香蕉 | 国产精品黄页免费高清在线观看 | 欧美日韩精品免费在线观看视频| 国产精品啪啪啪视频| 国产日韩中文在线| 亚洲欧洲精品一区二区三区波多野1战4| 久久精品综合一区| 免费在线a视频| 一区二区三区视频| 国产v亚洲v天堂无码久久久| 激情内射人妻1区2区3区| 久久久久久国产精品美女| 国产l精品国产亚洲区久久| 国内精久久久久久久久久人| 亚洲一区久久久| 日韩视频欧美视频| 成人免费福利在线| 日韩美女视频中文字幕| 久久国产天堂福利天堂| 九色综合日本| 国产女主播自拍| 青青在线免费观看| 亚洲一区影院| 国产精品户外野外| 国产l精品国产亚洲区久久| 国模精品娜娜一二三区| 色噜噜狠狠色综合网| 精品久久免费观看| 久久久久久香蕉网| 99精品国产高清一区二区| 激情五月宗合网| 亚欧洲精品在线视频免费观看| 国产精品视频久久久久| 久久久影院一区二区三区| 免费看成人午夜电影| 日本福利视频导航| 在线视频一二三区| 国产精品国产福利国产秒拍| 久久福利电影| 国产精品99久久久久久久| 国产免费一区二区| 国内精品视频在线| 日韩精品成人一区二区在线观看| 一区二区三区欧美在线| 国产精品无码人妻一区二区在线 | 国产精品成人av性教育| 国产a视频免费观看| 不卡一区二区三区视频| 精品视频一区二区| 欧美亚洲第一区| 日韩精品一区中文字幕| 色播亚洲婷婷| 亚洲一区二区三区免费看| 精品国产三级a∨在线| 久久视频在线观看免费| 久草资源站在线观看| 91av在线网站| av色综合网| 国产精品亚洲欧美导航| 精品少妇在线视频| 欧美日韩亚洲一区二区三区在线观看| 欧美一级日本a级v片| 一本久久a久久精品vr综合| 精品九九九九| 国产精品对白刺激| 国产精品国产一区二区| 国产精品久久久久99| 国产精品免费小视频| 久久最新资源网| 国产精品无码一区二区在线 | 国产欧美日韩视频一区二区三区| 国内精品久久久久久中文字幕| 青草青草久热精品视频在线观看 | 亚洲一区二区三区视频播放| 一本色道久久99精品综合| 一区二区三区四区视频在线| 欧美日韩国产第一页| 欧美激情视频网站| 中文字幕精品一区日韩| 亚洲淫片在线视频| 黄色录像特级片| 欧美污视频久久久| 欧美在线激情网| 激情视频一区二区| 精品午夜一区二区| 国产日韩精品久久| 国产精品一区久久| 国产乱子伦精品| www国产无套内射com| 91精品国产91久久久久久吃药| 99在线影院| 97精品久久久| 国产高潮呻吟久久久| 久久人人爽国产| 久久草视频在线看| 日韩在线观看你懂的| 国产精品欧美风情| 萌白酱国产一区二区| 亚洲天堂第一区| 日产精品高清视频免费| 日韩免费在线视频| 激情小说综合区| 成人免费网视频| 国产成人精品免高潮在线观看| 国产成人无码精品久久久性色| 国产精品久久久av| 一区二区在线观| 日韩不卡av| 黄色高清无遮挡| 国产伦精品一区二区三区高清版 | 成人久久一区二区三区| 久久偷窥视频| 久久久久久国产三级电影| 国产精品国产精品| 亚洲高清不卡一区| 欧美做受高潮1| 国产私拍一区| 国产盗摄xxxx视频xxx69| 国产精品精品一区二区三区午夜版| 亚洲综合国产精品| 欧美理论一区二区| www.浪潮av.com| 久久久久久亚洲| 久久99久久99精品免观看粉嫩| 午夜精品一区二区三区视频免费看| 欧美中文在线观看国产| 国产美女直播视频一区| 国产成人在线一区| 久久夜色精品国产亚洲aⅴ| 五码日韩精品一区二区三区视频 | 日韩av免费电影| 精品一区日韩成人| 国产成人自拍视频在线观看| 久久精品最新地址| 亚洲一区二区在线免费观看| 日本一区二区高清视频| 国产主播在线看| 久久99精品久久久久久久青青日本| 欧美成aaa人片免费看| 日批视频在线免费看| 国产一区二区网| 久久99蜜桃综合影院免费观看| 国产精品久久久久77777| 性高湖久久久久久久久aaaaa| 麻豆av一区| 日韩在线一区二区三区免费视频| 中国人体摄影一区二区三区| 欧美亚洲色图视频| 99精品人妻少妇一区二区| 久久这里只有精品99| 品久久久久久久久久96高清| 91久久精品视频| 精品久久久久久久久久中文字幕| 日韩久久一级片| 久久亚洲中文字幕无码| 亚洲熟女乱色一区二区三区| 国产午夜精品一区| 久久久www成人免费精品| 日本精品久久久久久久|