Introduction
这是接上次作业的第二部分,需要实现整个聊天通信的大体框架,包括服务端Server和客户端Client的编程。
这部分主要是实现Server端的编程,涉及到多路I/O复用(select/poll/epoll),Socket编程等。
Wolfie Chat Overview
The Wolfie Chat program will allow users logged into the the Wolfie Chat
server to send messages to each other. Chats between users will each be
displayed on the client machine in independent windows, just as Google
Hangouts does.
Clients will attempt to establish a connection with the server through the
accept thread. The accept thread on the server will create a connection with
the Client and spawn the Login Thread. The Login thread will then communicate
with the client via the Wolfie Protocol to successful/unsuccessfully log the
user into the Wolfie Chat system. Upon successful/unsuccessful login, the
Login thread will terminate. A Login thread will be created for each
connection attempt and terminated upon completion. Multiple login threads can
exist simultaneously if multiple users are attempting to login.
If the user is successfully logged on, then the server will act as the middle
man for all communications between the users connected to the server. A
Communication thread on the server will be spawned when the first user logs
onto the server and terminate when no user is logged in. This thread will then
service all additional users who connect. An overview of the architecture is
shown below.
Part I - Establishing a connection
In this part we will work on establishing a simple login procedure between the
client and server program. At the end of it you should have multiple users
logged in who can simply ask the server “how long have I been connected”. The
server should then respond to the correct user and let them know how long.
Also the client should be able to ask “who else is connected” and the server
will return a list of connected users. Once this part is completed, you should
be able to extend the concepts to make a more complex application which will
allow users connected with the server to communicate with each other.
Server
Below is a diagram representing the internal control flow of the server
program. As discussed above this is the main accept thread which is running
when the server program is run. Login threads are spawned as necessary to
handle each user’s login attempt. A successfully logged in user then
communicates with the server via the communication thread.
Accept Thread (main())
The primary server program will accept commands from the user via stdin and
connections from the client program via the bound “listen” socket. When the
server accepts an incoming connection from a client it should spawn a new
login thread and begin the login process. If it detects input from the
keyboard, it should parse that input for a list of commands and handle it
accordingly. This section of the process will use a form of I/O multiplexing
to listen for input on both the server socket and from stdin.
I/O multiplexing is exposed via the following interfaces - select, poll, or
epoll. They all have their pros and cons, but it is up to you to choose which
technique you should use. You will use I/O multiplexing in both the server and
your client program. In your server, you will multiplex on each socket for the
connected users in the communication thread, and in the accept thread you will
multiplex on the accept socket and stdin.
The benefits of I/O multiplexing are that the program will be put into a
suspended state while no activity is being performed on the fd’s, and when one
of the fd’s is written to, it will alert your program that something happens,
and you can then act on it. The other benefits to these techniques is that
they work in a synchronous manner, but allow you to have behavior similar to
doing things concurrently, without the overhead of spawning new threads, or
starting new processes.
Login Thread
When a client connects to the server, the server should spawn a thread to
handle the login protocol with the server. The login protocol is defined later
in Part I. The Login thread will need to check the list of users on the server
(shared resource between server threads) to see if the username is already in
use. If the name is not in use, the login thread will then complete the
protocol to log the user into the server. We will simply treat login for this
part as a first come first serve process. If student1 logs in as user1 then
student2 tries to login as user1, student1 will successfully log in and
student2 will be rejected. Any relevant data about the connecting user should
be a of structure you define that makes their information easily accessible.
An in-exhaustive list of things relevant to save are: the time of login, the
socket on which they communicate, the username, and the ip address. You are
encouraged to add any other fields of data that assist in your implementation.
Communication Thread
When there is at least one user logged in to the server a thread must be
spawned to handle the communication to and from the server and later between
all of the clients. In your communication thread you will use I/O multiplexing
on the set of file descriptors (fds) used to communicate with the clients.
You must use I/O multiplexing.
Usage
./server [-h|-v] PORT_NUMBER MOTD
-h Displays help menu & returns EXIT_SUCCESS.
-v Verbose print all incoming and outgoing protocol verbs & content.
PORT_NUMBER Port number to listen on.
MOTD Message to display to the client when they connect.
Remember that options in [] are considered optional, and arguments which are
not assigned a flag are positional.
- When the server is first started it should print out which port it is currently listening on.
$ ./server 3200 “Welcome to the cse320 chat server!”
Currently listening on port 3206.You should set up a signal handler so that if ctrl-c is pressed, it should
close the socket correctly. If you don’t close the socket correctly, you may
have to wait for the OS to clean it up which sometimes happens instantly,
and other times you have to wait up to 5 minutes. This can be annoying
during development and grading. - To make things easier to read, you should use the following ansii escape codes to help color your messages on the server screen.
Verbose Errors Default
\x1B[1;34m \x1B[1;31m \x1B[0mIf you don’t remember what the ansii escape codes are/do take a look were.
Server commands
Aside from handling connections from various clients, the server also has to
handle input from stdin. This input should represent commands that the person
operating the server might want to use. These commands are transparent to the
clients connected and are mainly used as a way to gather information by the
server operator.
/users
When /users is typed into the server’s terminal it should dump a list of
currently logged in users to stdout (NOTE: this does not send anything over
the network, this is only on the server side.). This can be a great way to
debug your program, it is advised you take some time to make neatly formatted
print statements that print out relevant data. (Think, toString() function for
your user structs).
/help
When /help is typed into the server’s terminal it should list all the commands
which the server accepts and what they do.
/shutdown
When /shutdown is typed into the server’s terminal it should cleanly
disconnect all connected users. Save any state that it must and then close all
the sockets and files which it is using and free any heap memory allocated.