| | |
UDP-Sockets chat application question
Please support our C++ advertiser: Intel Parallel Studio Home
![]() |
Hi to everyone!
I want to create a simple chat application using udp sockets. I want to have 2 applications that will be able to talk to each other.In particular app1 will send msgs to p2 and p2 will display them in stdout. Then maybe p2 sends a msg to p1... etc..
for the initialization part i have the following:
-->> server part initialization.
-->> client part initialization
-->> fork so that the application will be able to send and receive messages.
here are some extra functions:
also the functions with the first letter capitalized are from stevens's "unix network programming".
I have to questions in the above scheme:
First, is this the "best" way to tackle the chat problem? or am i missing something in the big picture
Second, it fails to work in the following sense:
each time i try to send something from app1 to app2.
app2 never receives the msg... but instead app1 does! why? and how can i fix it...
any ideas {even if not complete} are welcome!
thanks for your help,
nicolas
I want to create a simple chat application using udp sockets. I want to have 2 applications that will be able to talk to each other.In particular app1 will send msgs to p2 and p2 will display them in stdout. Then maybe p2 sends a msg to p1... etc..
for the initialization part i have the following:
-->> server part initialization.
c++ Syntax (Toggle Plain Text)
if (argc != 4) err_quit("usage: udpcli <IPaddress> <his-Port> <mine-Port>\n"); sockfd = Socket(AF_INET, SOCK_DGRAM, 0); memset( &servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(atoi( argv[3]) ); //servaddr.sin_port = htons( SERVER_PORT ); Bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr) ); printf("Peer-Server initiated...listening in %s and port %d\n\t waiting for clients\n", argv[1], ntohs(servaddr.sin_port));
c++ Syntax (Toggle Plain Text)
memset( &hisaddr, 0, sizeof(hisaddr) ); hisaddr.sin_family = AF_INET; hisaddr.sin_port = htons( atoi(argv[3]) ); Inet_pton( AF_INET, argv[1], &hisaddr.sin_addr);
c++ Syntax (Toggle Plain Text)
if((childpid = fork()) == 0) { //send message to peer peer_dg_send(stdin, sockfd, (struct sockaddr *) &hisaddr, sizeof(hisaddr)); } else { //receive message from peer peer_dg_receive(sockfd, (struct sockaddr *) &hisaddr, sizeof(hisaddr) ); }
here are some extra functions:
c++ Syntax (Toggle Plain Text)
void peer_dg_receive(int sockfd, struct sockaddr * pcliaddr, socklen_t clilen) { int n; socklen_t len; char mesg[MAXLINE]; for(;;) { len = clilen; n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len); mesg[n] = 0; /* null terminate */ //Fputs(mesg, stdout); printf("Received: %s", mesg); } } void peer_dg_send(FILE *fp, int sockfd, struct sockaddr *pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE]; while (Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); } }
I have to questions in the above scheme:
First, is this the "best" way to tackle the chat problem? or am i missing something in the big picture
Second, it fails to work in the following sense:
each time i try to send something from app1 to app2.
app2 never receives the msg... but instead app1 does! why? and how can i fix it...
any ideas {even if not complete} are welcome!
thanks for your help,
nicolas
Two roads diverged in a wood, and I— I took the one less traveled by, and that has made all the difference.
by Robert Frost the "The Road Not Taken"
by Robert Frost the "The Road Not Taken"
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
First, is this the "best" way to tackle the chat problem?
no. it is unlikely that someone would want to set up a chat between two processes on the same machine, sharing stdin and stdout between them. write two separate programs; the server and the client. which can be run on different machines.
> each time i try to send something from app1 to app2.
> app2 never receives the msg... but instead app1 does! why?
i've only had a cursory look, but:
the forked child process has its own copy of the parent's descriptors.
but these descriptors reference the same underlying objects as the parent.
both the parent and child processes are using the same socket, same stdin etc.
no. it is unlikely that someone would want to set up a chat between two processes on the same machine, sharing stdin and stdout between them. write two separate programs; the server and the client. which can be run on different machines.
> each time i try to send something from app1 to app2.
> app2 never receives the msg... but instead app1 does! why?
i've only had a cursory look, but:
the forked child process has its own copy of the parent's descriptors.
but these descriptors reference the same underlying objects as the parent.
both the parent and child processes are using the same socket, same stdin etc.
•
•
•
•
First, is this the "best" way to tackle the chat problem?
no. it is unlikely that someone would want to set up a chat between two processes on the same machine, sharing stdin and stdout between them.
University assignment dictates that we do a chat "system" with 2 udp connected peers. In this sense we can't have
a single server, but a lot of peers. So i figured that each peer will be both a server for the other peer,
and a client inorder to talk to some other peer.
i read somewhere that sockets are full duplex, so initially i tried to build an architecture like this:
C++ Syntax (Toggle Plain Text)
+---------------+ +---------------+ | | | | | peer1 | | peer2 | | |port1 port2| | | sock----|---------------|----sock | | | | | | | | | +---------------+ +---------------+
Where each peer will fork and run like this
c++ Syntax (Toggle Plain Text)
if((childpid = fork()) == 0) { //sending messages to other peer } else { //receiving message from other peer }
Unfortunatelly this didn't work. The reason was that no message ever reached the other peer. i.e. if i tried to send
from peer1 to peer2, then peer1 sent the message and peer1-child received it.
So one question is: is it possible to have a full duplex communication using only one process?
If yes, how?
If not, why?
So i decided to change the architecture and create 2 sockets. The scheme i created resembled this:
C++ Syntax (Toggle Plain Text)
+-------------------------------+ +-----------------------+ | | | | | peer1 | | peer2 | | |port1 port2| | | listening socket -------|---------------|----sending socket | | | | | | | | | | |port2 port1| | | sending socket----------|---------------|----listening socket | | | | | | | | | +-------------------------------+ +-----------------------+
this way when the process forks.The child is responsible for sending and the parent for listening.
With this scheme everything works great! There is only one small problem, concerning the peer as whole.
PeerX process runs on a terminal, so the terminal is used for stdout {receiving messages}
and stdin {writing messages}. So there are problems while you are writing a message and at the same time
you receive one.
In this point i have to more questions:
1) Is there anyway to divert stdin {or stdout} to another terminal. I know that i can divert it to a file
but because i want live communication, it isn't convienient...
2) Could this diversion be "easily" done, by using ncurses and creating something like this:
C++ Syntax (Toggle Plain Text)
+-------------------------------+ | | | | | stdout | | {messages received} | | | +-------------------------------+ | | | | | stdin | | {messages i type} | | | +-------------------------------+
any ideas are welcome, even if not complete....
-nicolas
Two roads diverged in a wood, and I— I took the one less traveled by, and that has made all the difference.
by Robert Frost the "The Road Not Taken"
by Robert Frost the "The Road Not Taken"
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
> i read somewhere that sockets are full duplex, so initially i tried to build an architecture like this:
a socket is *one* end of a two-way communications link.
a BSD socket maintains a separate send buffer and a receive buffer, and is full-duplex (you can both send and receive data on it).
to send or receive data, you need two sockets (one at either end).
in your first example, you are trying to use the *same* socket at both ends.
create *two* sockets, one for the client and another for the server.
(eg. socketpair does this for UNIX sockets. http://www.freebsd.org/cgi/man.cgi?query=socketpair)
after forking, close the client socket in the server, and the server socket in the client.
and things should be ok.
> Could this diversion be "easily" done, by using ncurses
yes.
a socket is *one* end of a two-way communications link.
a BSD socket maintains a separate send buffer and a receive buffer, and is full-duplex (you can both send and receive data on it).
to send or receive data, you need two sockets (one at either end).
in your first example, you are trying to use the *same* socket at both ends.
create *two* sockets, one for the client and another for the server.
(eg. socketpair does this for UNIX sockets. http://www.freebsd.org/cgi/man.cgi?query=socketpair)
after forking, close the client socket in the server, and the server socket in the client.
and things should be ok.
C++ Syntax (Toggle Plain Text)
+---------------+ +---------------+ | | | | | peer1 | | peer2 | | |port1 port2| | | sock1----|---------------|----sock2 | | | | | | | | | +---------------+ +---------------+
> Could this diversion be "easily" done, by using ncurses
yes.
Thanks for your answers vijayan,
nice explanation!
but:
>http://en.wikipedia.org/wiki/Duplex_(telecommunications)
As far as i can understand full-duplex is called when you can send and receive at the same time. So if a socket is a full duplex communications endpoint then you can send and receive data at the same time {from the same endpoint}. In the first example i wanted to do exactly this thing that is send and listen at the same time. Because these procedures are blocking, i thought that a way to circumvent this behaviour was to create a fork...
but i don't have a client-server scheme but a peer-to-peer scheme. The way i see it each peer must be a client and a server at the same time. Is there any other way to make peer-to-peer conversation? I am asking because it is the first i get exposed to the concept of p2p communication and not client-server
I can't use socketpair because according to the man page and i want internet domain....
I will try to do it this weekend...
Thanks again for your effort and your time,
Although i have a found a kind of solution to this problem {the one i posted in my second post with the use of 2 sockets per peer}, i keep asking because either i don't understand the concept of a socket, port,etc,... or i am doing something terribly wrong...
with regards,
nicolas
PS: as a side effect question what is the relation between a socket and a port. I mean a socket is a special kind of file descriptor, since when i use file descriptors i don't use ports, why we have to use ports when we use a socket?
•
•
•
•
a socket is *one* end of a two-way communications link.
a BSD socket maintains a separate send buffer and a receive buffer, and is full-duplex (you can both send and receive data on it). to send or receive data, you need two sockets (one at either end).
but:
>http://en.wikipedia.org/wiki/Duplex_(telecommunications)
•
•
•
•
in your first example, you are trying to use the *same* socket at both ends.
•
•
•
•
create *two* sockets, one for the client and another for the server.
•
•
•
•
(eg. socketpair does this for UNIX sockets. http://www.freebsd.org/cgi/man.cgi?query=socketpair)
after forking, close the client socket in the server, and the server socket in the client.
and things should be ok.
C++ Syntax (Toggle Plain Text)
+---------------+ +---------------+ | | | | | peer1 | | peer2 | | |port1 port2| | | sock1----|---------------|----sock2 | | | | | | | | | +---------------+ +---------------+
•
•
•
•
This call is currently implemented only for the UNIX domain.
•
•
•
•
> Could this diversion be "easily" done, by using ncurses
yes.
Thanks again for your effort and your time,
Although i have a found a kind of solution to this problem {the one i posted in my second post with the use of 2 sockets per peer}, i keep asking because either i don't understand the concept of a socket, port,etc,... or i am doing something terribly wrong...
with regards,
nicolas
PS: as a side effect question what is the relation between a socket and a port. I mean a socket is a special kind of file descriptor, since when i use file descriptors i don't use ports, why we have to use ports when we use a socket?
Two roads diverged in a wood, and I— I took the one less traveled by, and that has made all the difference.
by Robert Frost the "The Road Not Taken"
by Robert Frost the "The Road Not Taken"
•
•
Join Date: Dec 2006
Posts: 1,089
Reputation:
Solved Threads: 164
> what is the relation between a socket and a port.
> I mean a socket is a special kind of file descriptor
> when i use file descriptors i don't use ports
> why we have to use ports when we use a socket?
a socket has no relation to a port.
a socket is created with the socket function has no name. this is no different from other file descriptors. a file descriptor also has no name. for example, stdin, stdout, stderr are file descriptors.
you use the open function to create a descriptor, the name that you give is the name of a file in the filesystem (which has an existence independant of file descriptors).
a remote process has no way to refer to a socket until a name (an address) is bound to it. an address is given to a socket via the bind function call. the address serves as a unique name using which a socket can be referred to.
In the UNIX domain, an address is simply a filesystem path. eg.
The file name referred to is created as a socket in the system file name space. (write permission in the directory is required). these can be deleted with unlink().
in the Internet domain, the name is a tuple consisting of the IP address and a port number. a connection is a *unique* ordered tuple ( protocol, local ip address, local port, remote ip address, remote port). ports are an artifact of the addressing scheme to facilitate distinguishing between different connections on the same host (by composing unique tuples - at least the port is different - for each connection).
the same socket can be used to send and receive data at the same time. the following example would work, though we use the same socket:
ps1: run with peer address "127.0.0.1" (localhost) for testing.
ps2: if you have follow-up questions that you want me to answer, do not post them in daniweb. i keep away from web sites that behave as if Internet Explorer is the only browser that i should use. (this post is from IE/Wine). you could use http://forums.devx.com/forumdisplay.php?s=&forumid=110
instead, which is the (only) other C++ student's forum that i look at on a somewhat regular basis.
> I mean a socket is a special kind of file descriptor
> when i use file descriptors i don't use ports
> why we have to use ports when we use a socket?
a socket has no relation to a port.
a socket is created with the socket function has no name. this is no different from other file descriptors. a file descriptor also has no name. for example, stdin, stdout, stderr are file descriptors.
you use the open function to create a descriptor, the name that you give is the name of a file in the filesystem (which has an existence independant of file descriptors).
a remote process has no way to refer to a socket until a name (an address) is bound to it. an address is given to a socket via the bind function call. the address serves as a unique name using which a socket can be referred to.
In the UNIX domain, an address is simply a filesystem path. eg.
C++ Syntax (Toggle Plain Text)
sockaddr_un addr; ... std::strcpy( addr.sun_path, "/tmp/my_socket" ) ; addr.sun_family = AF_UNIX ; bind ( ... (sockaddr*) &addr, .... ) ;
in the Internet domain, the name is a tuple consisting of the IP address and a port number. a connection is a *unique* ordered tuple ( protocol, local ip address, local port, remote ip address, remote port). ports are an artifact of the addressing scheme to facilitate distinguishing between different connections on the same host (by composing unique tuples - at least the port is different - for each connection).
the same socket can be used to send and receive data at the same time. the following example would work, though we use the same socket:
c++ Syntax (Toggle Plain Text)
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <iostream> #include <cstring> #include <string> enum { RECV_PORT = 5000, MSGSIZE = 1024 }; socklen_t addr_len = sizeof(sockaddr) ; int listener( int socket_fd ) { sockaddr_in my_addr ; std::memset( &my_addr, 0, sizeof(my_addr) ) ; my_addr.sin_family = AF_INET ; my_addr.sin_port = htons( RECV_PORT ) ; my_addr.sin_addr.s_addr = INADDR_ANY ; if ( bind( socket_fd, (sockaddr*)&my_addr, addr_len ) != 0 ) return 2 ; while( true ) { char recv_data[MSGSIZE+1] ; sockaddr_in client_addr ; int bytes_recd = recvfrom( socket_fd, recv_data, MSGSIZE, 0, (sockaddr*)&client_addr, &addr_len ) ; if( bytes_recd == -1 ) break ; recv_data[bytes_recd] = '\0' ; std::cout << "from " << inet_ntoa(client_addr.sin_addr) << ':' << ntohs(client_addr.sin_port) << " - " << recv_data << std::endl ; } return 0 ; } int sender( int socket_fd ) { std::cout << "address of peer? " ; std::string address ; std::cin >> address >> std::ws ; sockaddr_in peer_addr ; std::memset( &peer_addr, 0, sizeof(peer_addr) ) ; peer_addr.sin_family = AF_INET ; peer_addr.sin_port = htons( RECV_PORT ) ; peer_addr.sin_addr.s_addr = *(in_addr_t*)(gethostbyname( address.c_str() )->h_addr) ; std::string send_str ; while( std::getline( std::cin, send_str ) ) { send_str.resize(MSGSIZE) ; sendto( socket_fd, send_str.c_str(), MSGSIZE, 0, (sockaddr*)&peer_addr, addr_len ) ; } return 0 ; } int main() { int socket_fd = socket( AF_INET, SOCK_DGRAM, 0 ) ; if( socket_fd == -1 ) return 1 ; return fork() == 0 ? listener( socket_fd ) : sender( socket_fd ) ; }
ps1: run with peer address "127.0.0.1" (localhost) for testing.
ps2: if you have follow-up questions that you want me to answer, do not post them in daniweb. i keep away from web sites that behave as if Internet Explorer is the only browser that i should use. (this post is from IE/Wine). you could use http://forums.devx.com/forumdisplay.php?s=&forumid=110
instead, which is the (only) other C++ student's forum that i look at on a somewhat regular basis.
![]() |
Similar Threads
- Thread's colliding? (C#)
Other Threads in the C++ Forum
- Previous Thread: flashing characters (without clearing the screen)
- Next Thread: Help with instance of one class in another
| Thread Tools | Search this Thread |
api array based binary c++ c/c++ calculator char char* class classes code coding compile console conversion count database delete deploy desktop developer directshow dll download dynamic dynamiccharacterarray email encryption error file forms fstream function functions game givemetehcodez google graph gui homeworkhelp iamthwee ifstream input int integer java lib linkedlist linker linux list loop looping loops map math matrix memory multiple news number numbertoword output parameter pointer problem program programming project python random read recursion recursive reference return rpg sorting string strings struct temperature template templates test text text-file tree unix url variable vector video visualstudio win32 windows winsock wordfrequency wxwidgets






