Solved

CSocket Question

Posted on 2003-11-26
2
634 Views
Last Modified: 2013-11-20
Ok...I am trying to understand the DCC SEND specs that I have. However, I am not having any luck. Hopefully someone can help. Here is what I have from the spec document:

      Create a socket, bind it to INADDR_ANY, port 0, and
            make it passive (a listening socket).
      Send the recipient a DCC request via CTCP supplying
            the address and port of the socket. (This
            is ideally taken from the address of the local
            side of the socket which is connected to a
            server. This is presumably the interface on
            the host which is closest to the rest of
            the net, and results in one less routing hop
            in the case of gateway nodes).
      Continue normally until a connection is received.

      On a connection:
      Accept the connection.
      Close the original passive socket.
      Conduct transaction on the new socket.


My questions are this. How do I make a passive socket as described using CSocket? Where does the port come from...why are they suggesting port 0. Why set up a socket to listen...close and open another? Can anyone help make sense of this?
0
Comment
Question by:SGyves
2 Comments
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 500 total points
ID: 9826669
I do know nothing about DCC but a little about sockets:

And i found the article below in MSDN (...\MSDN98\98VSa\1033\conf.chm::/html/SA2B7.HTM)

>How do I make a passive socket as described using CSocket?

You have to Create() the socket and call Listen() to make the socket listening for incoming requests.
With Accept() you accept a client that tried to Connect() to your server.

>Where does the port come from...why are they suggesting port 0
 
Port 0 means that your server is listening to all ports (i don't know whether this makes sense).
Some servers are listening to all ports because they don't know the port numbers clients will connect to.
I don't know whether this possible with CSocket because port number 0 means that MFC will choose a port number for you.

Normally, you would choose a unique port number - not used elsewhere in your system - say 35791
or any other odd number greater than 1024 and less than 65535 that is well known by server and client.

>Why set up a socket to listen...close and open another?

The server has to listen for clients. If a client connects this accepted connection needs another socket to do communication between server and client. The server socket still lives and listens for further connections.

Regards, Alex



-----------------------------------------------------------------------------------------------------------------
Setting Up Client and Server Sockets
Most Windows Sockets applications are asymmetrical; that is, there are generally two components to the network application—a client and a server. Frequently, these components are isolated into separate programs. Sometimes, these components are integrated into a single application (such as our sample application). When both the client and server components of a networking application are integrated, the application is generally referred to as a "peer" application. Both the client and the server components go through different procedures to ready themselves for networking by making a number of Windows Sockets API calls. The following state diagrams illustrate the state transitions for setting up client- and server-side socket applications:




Setting up a server-side stream-based application



Setting up a client-side stream socket-based application

The socket() call creates an endpoint for both client- and server-side application communication. When calling socket(), the application specifies the protocol family and either the socket type (stream or datagram), or the specific protocol which it expects to use (for example, TCP). Both the client- and server-side of a network application use the socket() call to define their respective endpoints. socket() returns a socket descriptor, an integer which uniquely identifies the socket created within Windows Sockets.

Server-side connection setup
Once the socket is created, the server-side associates the freshly created socket descriptor and a local endpoint address via the bind() API. The local endpoint address is comprised of two pieces of data, the IP address and the port ID for the socket. The local IP address is used to determine which interfaces the server application will accept connection requests on; the port ID identifies the TCP or UDP port on which connections will be accepted. It is for these two values that the network byte-ordering routines (htonl(), htons(), etc.) were created. These values must always be represented in network byte order.

Alternatively, an application may substitute the value INADDR_ANY in place of a valid local IP address, and the system will accept incoming requests on any local interface, and will send requests on the "most appropriate" local interface. In fact, most server applications do exactly this. To associate a socket with any valid system port, provide a value of 0 for the .sin_port member of the sockaddr_in structure. This will select an unused system port between 1025 and 5000. As mentioned before, most server applications listen on a specified port, and client applications use this mechanism to obtain an unused local port. Once an application uses this mechanism to obtain a valid local port, it may call getsockname() to determine the port the system selected.

The listen() API sets up a connection queue. It accepts only two parameters, the socket descriptor and the queue length. The queue length identifies the number of outstanding connection requests that will be allowed to queue up on a particular port/address pair, before denying service to incoming connections.

The accept() API completes a stream-based server-side connection by accepting an incoming connection request, assigning a new socket to the connection, and returning the original socket to the listening state. The new socket is returned to the application, and the server can begin interacting with the client over the network.

Client-side connection setup
From the client's perspective, the application also creates a socket using the socket() call. The bind() command is used to bind the socket to a locally specified endpoint address which the server will use to transmit data back to the client. Once a local endpoint association is made, the connect() API establishes a connection with a remote endpoint. This routine initiates the network connection between the two systems. Once the connection is made, the client can begin interaction with the server on the network.

Although the client may choose to call bind(), it is not necessary to do so. Calling connect() with an unbound socket will simply force the system to choose an IP interface and unique port ID and mark the socket as bound. Most client-side applications neglect the bind() call as there are rarely specific requirements for a particular local interface/port ID pair.

The following code fragments create and connect a pair of stream-based sockets using the API flow outlined above:

Server-side (connection-oriented)



#define            SERVICE_PORT        5001

SOCKET             srv_sock,        cli_sock;
struct sockaddr_in        srv_addr,        cli_addr;
char             buf[MAX_BUF_LEN];

/* Create the server-side socket */

srv_sock=socket(AF_INET,SOCK_STREAM,0);
if (srv_sock==INVALID_SOCKET){
    sprintf(buf,"Windows Sockets error %d: Couldn't create socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

srv_addr.sin_family=AF_INET;
srv_addr.sin_addr.s_addr=INADDR_ANY;
srv_addr.sin_port=SERVICE_PORT;        /* specific port for server to listen on */

/* Bind socket to the appropriate port and interface (INADDR_ANY) */

if (bind(srv_sock,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){
    sprintf(buf,"Windows Sockets error %d: Couldn't bind socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);    
    shutdown_app();
}

/* Listen for incoming connections */

if (listen(srv_sock,1)==SOCKET_ERROR){

    sprintf(buf,"Windows Sockets error %d: Couldn't set up listen on socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

/* Accept and service incoming connection requests indefinitely */

for ( ; ; ) {
    cli_sock=accept(srv_sock,(LPSOCKADDR)&cli_addr,&addr_len);
    if (cli_sock==INVALID SOCKET){
   
        sprintf(buf,"Windows Sockets error %d: Couldn't accept incoming \
             connection on socket.",WSAGetLastError());
        MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);    
        shutdown_app();
    }
    .
    /* Client-server network interaction takes place here */
    .
    closesocket(cli_sock);
}
Client-side (connection-oriented)



/* Static IP address for remote server for example. In reality, this would be    
   specified as a hostname or IP address by the user */

#define    SERVER        "131.107.1.121"        

struct     sockaddr_in    srv_addr,cli_addr;
LPSERVENT            srv_info;
LPHOSTENT            host_info;
SOCKET            cli_sock;
.
/* Set up client socket */

cli_sock=socket(PF_INET,SOCK_STREAM,0);

if (cli_sock==INVALID_SOCKET){
   
    sprintf(buf,"Windows Sockets error %d: Couldn't create socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

cli_addr.sin_family=AF_INET;
cli_addr.sin_addr.s_addr=INADDR_ANY;        
cli_addr.sin_port=0;                /* no specific port req'd */

/* Bind client socket to any local interface and port */

if (bind(cli_sock,(LPSOCKADDR)&cli_addr,sizeof(cli_addr))==SOCKET_ERROR){
   
    sprintf(buf,"Windows Sockets error %d: Couldn't bind socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

/* Get the remote port ID to connect to for FTP service */

srv_info=getservbyname("ftp","tcp");

if (srv_info== NULL) {

    sprintf(buf,"Windows Sockets error %d: Couldn't resolve FTP service port.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(SERVER);
srv_addr.sin_port=srv_info->s_port;

/* Connect to FTP server at address SERVER */

if (connect(cli_sock,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){

    sprintf(buf,"Windows Sockets error %d: Couldn't connect socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}
/* Client-server network interaction takes place here */
Although the above fragment makes use of the bind() API, it would be just as effective to skip over this call as there are no specific local port ID requirements for this client. The only advantage that bind() offers is the accessibility of the port which the system chose via the .sin_port member of the cli_addr structure which will be set upon success of the bind() call.

For connectionless, or "datagram" sockets, Windows Sockets usage is a little simpler. Since the communication in datagram sockets is connectionless, it is not necessary to use the APIs necessary for creating a connection, namely: connect(), listen(), and accept(). The flow of Windows Sockets APIs that a typical connectionless client-server pair will generally traverse follows:



Setting up a server-side datagram-based application



Setting up a client-side stream-based application

As pictured above, a client may choose to connect() the datagram socket for convenience of multiple sends to the remote endpoint. Connecting a datagram socket will cause all sends to go to the connected address, and any datagrams received from a remote address different than the connected address are discarded by the system. Generally, connectionless clients use the sendto() API to transmit application data. The sendto() call requires that the destination's endpoint address be specified with every call to the API. By connecting a datagram socket, a client sending a large amount of data to the same destination can simply use the send() API to transmit, without having to specify a remote endpoint with every call, and the client need not concern itself with the possibility of receiving unwanted data from other hosts. Depending on the type of application you are developing, and the Windows Sockets implementation below your application, connecting datagram sockets may improve performance of your application.

Some sample code illustrates how the TFTP protocol (a connectionless protocol for file transfer) client and server might be implemented over Windows Sockets:

Server-side (connectionless)



SOCKET             srv_sock;
struct sockaddr_in        srv_addr;

.
.
/* Create server socket for connectionless service */

srv_sock=socket(PF_INET,SOCK_DGRAM,0);

if (srv_sock==INVALID_SOCKET){

    sprintf(buf,"Windows Sockets error %d: Couldn't create socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

/* Resolve TFTP service port to listen on */

srv_info=getservbyname("tftpd","udp");

if (srv_info== NULL) {

    sprintf(buf,"Windows Sockets error %d: Couldn't resolve TFTPd service port.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = INADDR_ANY;   /* Allow the server to accept connections                         /* over any interface */
srv_addr.sin_port=srv_info->s_port;

/* Bind remote server's address and port */

if (bind(srv_sock,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){
   
    sprintf(buf,"Windows Sockets error %d: Couldn't bind socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

/* Client-server network interaction takes place here */

Client-side (connectionless)



/* Static IP address for remote server for example. In reality, this would be    
   specified as a hostname or IP address by the user */

#define    SERVER        "131.107.1.121"        

struct sockaddr_in        srv_addr,cli_addr;
LPSERVENT            srv_info;
LPHOSTENT            host_info;
SOCKET            cli_sock;

.
.
/* Create client-side datagram socket */

cli_sock=socket(PF_INET,SOCK_DGRAM);
if (cli_sock==INVALID_SOCKET){
   
    sprintf(buf,"Windows Sockets error %d: Couldn't create socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

cli_addr.sin_family=AF_INET;
cli_addr.sin_addr.s_addr=INADDR_ANY;        
cli_addr.sin_port=0;                /* no specific local port req'd */

/* Bind local socket */
if (bind(cli_sock,(LPSOCKADDR)&cli_addr,sizeof(cli_addr))==SOCKET_ERROR){
   
    sprintf(buf,"Windows Sockets error %d: Couldn't bind socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

/* Resolve port information for TFTP service */

srv_info=getservbyname("tftp","udp");
if (srv_info== NULL) {

    sprintf(buf,"Windows Sockets error %d: Couldn't resolve TFTP service port.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}

srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = inet_addr(SERVER);
srv_addr.sin_port=srv_info->s_port;

if (connect(cli_sock,(LPSOCKADDR)&srv_addr,sizeof(srv_addr))==SOCKET_ERROR){
    sprintf(buf,"Windows Sockets error %d: Couldn't connect socket.",
         WSAGetLastError());
    MessageBox (hWnd,buf,"Windows Sockets Error",MB_OK);
    shutdown_app();
}
/* Client-server network interaction takes place here */
Since a connectionless client (such as TFTP) will undoubtedly be doing successive transmissions with the server (especially during long transfers), we have chosen to connect the socket, allowing the use of the send() and recv() APIs rather than sendto() and recvfrom(). The use of connect() with datagram sockets is purely optional.

--------------------------------------------------------------------------------------------------
0
 

Expert Comment

by:shiju_luke
ID: 9826811
How do I make a passive socket as described using CSocket?
A passive socket is one that simply listens on the socket.  By creating a socket with SOCK_STREAM as the second parameter (nSocketType) and then calling the Listen method will make it passive.

Where does the port come from...why are they suggesting port 0.
Port 0 is the default.  Setting it to port 0 will force windows sockets to select a port.  This will mean that it will listen to all ports.  Use this when you're not sure what port is going to request a connection.

Why set up a socket to listen...close and open another?
Because you need to listen to the socket first.  Imagine you're waiting for a phone call.  You have to listen to the phone.  When the phone rings, you know someone is there and is trying to reach you.  Then you pick up the phone but the phone is listening for other calls if you have call waiting.  In the same way, you listen on a socket.  When it receives a request, you still need this socket to listen for other requests.  So you open a new socket connection to communicate while the old socket listens for more requests.

I hope this helps.




0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
MFC Dialog 9 47
Understanding the meaning of Portability in Embedded System Programming 8 110
deburging in oracle form 12 76
noX challenge 17 76
In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now