2015:03:16:chatclient

De wiki-prog
Révision de 19 mars 2015 à 08:21 par ASM (discuter | contributions) (Sockets)

(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)
Aller à : navigation, rechercher

Foreword

Issue your code

Make sure your code respects the following architecture:

$ find .
.
./AUTHORS
./README
./Makefile
./src
./src/chat.c

Notes (READ THIS)

  • The command ‘make’ must compile a program named ‘chat’ at the root of your repository.
  • chat.c doesn’t have to be your only source file. You can (and should) add other ones. Organize your code the way you want. Put your entry point (main() function) in chat.c though.
  • Your code must compile. You have to submit your Makefile. You learned a lot about Makefiles last week, you should be able to cope with this.
  • A server is running on 37.59.62.110 (too.gy) on port 4042. Confront your code to it.

Subject maintainers

Feel free to contact us with any question if something is unclear.

Networking and networking in C

Beej’s guide to Network Programming

There’s a great guide out there on the Internet. It’s the guide about networking in C, written by a guy who goes by the name of ‘Beej’:

  • French version: [1]
  • English version: [2]

Even if Marwan probably explained to you all the necessary things, you may have forgotten. So if you have any difficulty in understanding some concepts we are talking about in this subject, they’re all explained in this marvelous guide.

Sockets

A socket is a generalized interprocess communication channel. Like a pipe, a socket is represented as a file descriptor. Unlike pipes, sockets support communication between unrelated processes, and even between processes running on different machines that communicate over a network.

To have a useful socket, you have to:

  • Create a socket with the socket() system call
  • Connect the socket to the address of the server using the connect() system call
  • Send and receive data. There are a number of ways to do this, but the simplest is to use the read() and write() system calls.

All the basic functions needed for networking are explained here:

http://beej.us/guide/bgnet/output/html/multipage/syscalls.html

Chat Client

Today you will have to write a chat client from scratch.

Your program will have to connect to a chat server (written by us), identify, send and receive messages (printing them on stdout), etc. To avoid the read part to block the write part, we will use threads: don’t worry, you have the skeleton of it with some beautiful FIXME, so you don’t have to understand what threads are about and how to use them (well, not today).

You will have to respect our protocol of communication. A protocol is just a set of rules regarding the way our server and your client will communicate (without a protocol, we couldn’t understand each other!).

This subject is a series of levels. Try to pass as many of them as you can!

Foreword about the protocol

The protocol we will use is very simple (we wouldn’t use that in real life).

When the server and the client will communicate, we’ll say that they exchange packets.

We split the data with new line characters. The first line of the packet is the name of the packet. If you identify, the name will be IDENTIFY, if you join a chat room, it will be JOIN etc. This is constant for all the packets. What comes after this line will depend on the kind of packet and will be explained later on for each one of them. Just read the subject.

NOTE: Please read the server answers when you send packet to it. If you send an invalid packet the server will reply with:

INVALID_PACKET\n
<reason-why>

Level 1: open a socket connection with the server

When you open a socket, you connect to another machine (here, a chat server that is responsible for broadcasting the messages sent by the client to other chat rooms etc.). A server has a host name and listens on a port. So when you connect to it, you have to know both of them.

Your program must be called this way:

./chat -p 4242 -h 127.0.0.1

where the -p option allows the user to define the port the server listens to and the -h option allows the user to define the server’s host name.

To parse your input, you can use getopt() (see the GNU example of getopt) or you can do it the hard (and ugly) way using directly strcmp() with argv. We strongly recommand you getopt() since you will use it on many future projects (and it’s really easy to use once learned).

PASS THIS LEVEL: this is mandatory for other levels. If you can’t do it you vill git a zero anyway.

Level 2: identify to the server, disconnect from the server

Identify

When launching your chat client (and when the socket connection is made with the server), you have to ask the user for a username and identify him to the server. When the user lunches the client, he must see the following message:

You must identify yourself. Please write your login.\n
Login:

Then you must send the adequate packet to the server:

IDENTIFY packet:

IDENTIFY\n
<username>\n

PASS THIS LEVEL: identify to the server with your EPITA login.

Disconnect

To quit, the client must write /quit immediately followed by a newline. To properly disconnect from the server, send the following packet:

DISCONNECT\n

PASS THIS LEVEL: disconnect from the server while being identified with your login.

Level 3: join/leave a chat room

Send a join/leave packet

When the user write /join immediately followed by a newline, he must see the following message:

Write the name of the chat room you want to join:

JOIN packet:

JOIN\n
<chat-room-name>\n

Note that sending this packet requires that your are identified.

The server will reply with a packet containing:

JOINED\n
<chat-room-name>\n
<number-of-users-in-chatroom>\n
<user1>\n
<user2>\n
<user3>\n
...

(the list of all the users present in the chat room you just joined).

When the user wants to leave the chat room, he must write /leave immediately followed by a newline (writing the name is not useful since the user has only one current chat room).

LEAVE packet:

LEAVE\n
<chat-room-name>\n

The server will reply with a packet containing:

LEFT\n

PASS THIS LEVEL: join and leave the chatroom provided by your assistants (while being identified to the server with your login).

Receive join/leave packet (when someone joins a chat room)

When someone joins or leaves a chat room, the server will notify all the users that are in this specific chat room. You have to notify the user when someone join or leave the chat room like this:

--> <username> has joined <chat-room-name>\n
<-- <username> has quit <chat-room-name>\n

USERJOINED packet:

USERJOINED\n
<chat-room-name>\n
<username>\n

USERLEFT packet:

USERLEFT\n
<chat-room-name>\n
<username>\n

PASS THIS LEVEL: this will be tested on your submission.

Level 4: compose and send a message to a chat room

Your program, once connected, when the user logged in and joined a chatroom should provide him a way to send messages to the chat room.

Read the user’s message from stdin and send it to the server.

Note that the input is a “message” if it is neither /join\n, /leave\n or /quit\n.

MESSAGE packet (when sent by the client to the server):

MESSAGE\n
<chat-room-name>\n
<message-content>\n

Note that the content of a message cannot contain a newline character (it would be stripped then).

If all goes well, the server should reply with:

SENT\n

PASS THIS LEVEL: join the chatroom provided by your assistants and send a message (while being identified to the server with your login).

Level 5: receive and log messages from the server

Your program should also be able to receive messages sent by other people (and actually yours too because when you send a message to the server it is also sent back to you because it is broadcasted to the full chat room).

MESSAGE packet (when received by the client from the server):

MESSAGE\n
<chat-room-name>\n
<username>\n
<message-content>\n

(where <username> is the username of the person issuing the message) Log the messages once received into a file called <chatroom>.log. To see your file being modified “in live”, use:

tail -f <chatroom>.log

in another terminal. To open a file for writing at the end of it, see man 3 fopen.

The format of the logs must be :

HH:MM <[username]> [message]

For example, a message ‘Hello world!’ sent by toogy at 12:40 would be logged as:

12:40 <toogy> Hello world!

To get the current time, consider this example (see [[3]|http://linux.die.net/man/3/localtime]]):

struct tm *tm_struct = localtime(time(NULL));
printf("The time is %.2d:%.2d:%.2d\n",
        tm_struct->tm_hour, tm_struct->tm_min, tm_struct->tm_sec);

PASS THIS LEVEL: this will be tested on your submission.

Level 6: bonus

Got time? Sorry but, visually and ergonomically, your chat client sucks. Try to use the ncurses library to make it beautiful and user friendly. With ncurses you could display the incoming messages but still read the user input in the same time for him/her to be able to send messages. You could also make a buffer system to manage multiple chatrooms.