![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 | |
|
Professional Programmer
|
Network programming
I found a socket tutorial at this site... tutorial and decided i wanted to test out network programming.. so my first goal was to convert it mostly into C++, so now thats done and im just posting here for people to test it as it "grows up". Please feel free to drop a message in on the server by compiling this code, then follow the instructions bellow.
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <strings.h>
#include <iostream.h>
#define MAXPENDING 5
#define BUFFER_SIZE 1024
#define EXIT_CALL " exit"
int main()
{
int local_socket = 0, remote_socket = 0, menu_switch = 0, message_length = 0, remote_length = 0;
unsigned short local_port = 0, remote_port = 0;
struct sockaddr_in local_address, remote_address;
WSADATA wsa_data;
char message[BUFFER_SIZE], remote_ip[32];
cout << "Send data to server[1]\n";
cout << "Listen for data as server[2]\n";
cout << "Make your selection: ";
do {
cin.clear ();
if (cin.sync ());
cin >> menu_switch;
if (!cin.good ()) cout << "You must enter an integer: ";
} while (menu_switch == 0);
cout << "Enter local port to use: ";
do {
cin.clear ();
if (cin.sync ());
cin >> local_port;
if (!cin.good ()) cout << "You must enter a port: ";
} while (local_port == 0);
if (WSAStartup(MAKEWORD(2, 0), &wsa_data) != 0)
{
cout << "WSAStartup() failed\n";
return (1);
}
if ((local_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
cout << "socket() failed\n";
return(1);
}
/* Construct local address structure */
memset(&local_address, 0, sizeof(local_address)); /* Zero out structure */
local_address.sin_family = AF_INET; /* Internet address family */
local_address.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
local_address.sin_port = htons(local_port); /* Local port */
/* Bind to the local address */
if (bind(local_socket, (struct sockaddr *) &local_address, sizeof(local_address)) < 0)
{
cout << "bind() failed\n";
return(1);
}
switch (menu_switch)
{
case 1:
cout << "Enter server IP: ";
do {
cin.clear ();
if (cin.sync ());
cin >> remote_ip;
if (!cin.good ()) cout << "You must enter an ip: ";
} while (remote_ip == 0);
fflush(stdin);
cout << "Enter server Port: ";
do {
cin.clear ();
if (cin.sync ());
cin >> remote_port;
if (!cin.good ()) cout << "You must enter a port: ";
} while (remote_port == 0);
fflush(stdin);
if ((remote_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
cout << "socket() failed";
return(1);
}
memset(&remote_address, 0, sizeof(remote_address)); /* Zero out structure */
remote_address.sin_family = AF_INET; /* Internet address family */
remote_address.sin_addr.s_addr = inet_addr(remote_ip); /* Server IP address */
remote_address.sin_port = htons(remote_port); /* Server port */
if (connect(remote_socket, (struct sockaddr *) &remote_address, sizeof(remote_address)) < 0)
{
cout << "connect() failed";
return(1);
}
do
{
memset(&message, 0, BUFFER_SIZE);
cout << "Enter message to send: ";
gets(message);
fflush(stdin);
message_length = (strlen(message));
if (send(remote_socket, message, message_length, 0) != message_length)
{
cout << "send() failed";
return(1);
}
}
while(strcmp(message, EXIT_CALL));
break;
case 2:
/* Mark the socket so it will listen for incoming connections */
if (listen(local_socket, MAXPENDING) < 0)
{
cout << "listen() failed\n";
return(1);
}
remote_length = sizeof(remote_address);
for(;;)
{
/* Accepts an incoming connection when one is detected */
if((remote_socket = accept(local_socket, (struct sockaddr *) &remote_address, &remote_length) ) < 0)
{
cout << "accept() failed\n";
return(1);
}
else
{
break;
}
}
do
{
memset(&message, 0, BUFFER_SIZE);
/*receive the message from the client*/
if((message_length = recv(remote_socket, message, BUFFER_SIZE, 0)) < 0)
{
cout << "recv() failed\n";
return(1);
}
cout << "From client " << inet_ntoa(remote_address.sin_addr) <<": " << message << endl;
}
while(strcmp(remote_ip, EXIT_CALL));
break;
}
WSACleanup(); /* Cleanup Winsock */
closesocket(local_socket);
closesocket(remote_socket);
system("pause");
return(0);
}1. Compile then run the program 2. Send data to server[1] 3. Enter Local port to use: 51 4. Enter server IP: 70.80.252.72 5. Enter server Port: 50
__________________
▄▄▄▄ Quote:
Due to incorrect calculations during the middle ages, our calendar actually begins a few years after Jesus' birth. Thus the real 6/6/6 happened a few years back. The world already ended and you missed it. Download Code::Blocks now! ▄▄▄▄ |
|
|
|
|
|
|
#2 | |
|
Professional Programmer
|
edit time expired
anyways, I noticed that once anyone closes their client, the server closes too.. If anyone can look above and tell me how i would be able to close the client, without the server closing.. ive tried to get rid of the exit_call command and a few other things, not too sure how to do it though .. any help?
__________________
▄▄▄▄ Quote:
Due to incorrect calculations during the middle ages, our calendar actually begins a few years after Jesus' birth. Thus the real 6/6/6 happened a few years back. The world already ended and you missed it. Download Code::Blocks now! ▄▄▄▄ |
|
|
|
|
|
|
#3 |
|
Programmer
Join Date: Jun 2005
Posts: 99
Rep Power: 4
![]() |
revc() will return 0 if the connection has closed at the other end, it will then return <0 if you try to call recv() on the closed socket again. So you need to handle the 0 case to make sure your not trying to recv() on a closed socket.
|
|
|
|
|
|
#4 | |
|
Professional Programmer
|
i dont quite understand, i tried changing the < 0 and 0 flags around but it wouldnt exactly help, it would just close the server when i tried to send a message..
__________________
▄▄▄▄ Quote:
Due to incorrect calculations during the middle ages, our calendar actually begins a few years after Jesus' birth. Thus the real 6/6/6 happened a few years back. The world already ended and you missed it. Download Code::Blocks now! ▄▄▄▄ |
|
|
|
|
|
|
#5 |
|
Programmer
Join Date: Jun 2005
Posts: 92
Rep Power: 4
![]() |
Basically, what is happening is that recv is failing, so if you are checking for a return value of SOCKET_ERROR, and if found then exiting, the program finds SOCKET_ERROR and then exits. There are two solutions. One is to write using asynchronous (non-blocking) sockets, which would allow for multiple connections at once, assuming it is writen right. The other solution is make a while(1) loop starting before the call to listen, and ending after you close the connection. Then check if the return value of recv() is 0 and if so, close the socket, and go back to the top of the loop. In my opinion, the first solution is better, but it will require more time to be put into the program.
P.S. I haven't tried the second solution, so I'm not sure how well it would work, or if it WinSock would mess with the socket to the point where it wouldn't work. |
|
|
|
|
|
#6 | |
|
Professional Programmer
|
What im asking is how do i set recv() back to 1 or higher each loop? what do i do?
__________________
▄▄▄▄ Quote:
Due to incorrect calculations during the middle ages, our calendar actually begins a few years after Jesus' birth. Thus the real 6/6/6 happened a few years back. The world already ended and you missed it. Download Code::Blocks now! ▄▄▄▄ |
|
|
|
|
|
|
#7 |
|
Programmer
Join Date: Jun 2005
Posts: 99
Rep Power: 4
![]() |
Excuse the horrible pseudo code, but this is how I would lay out a multiple client server (with non-blocking sockets):
while( true )
{
if( ListenSocket.Listen() != error ) // accept new clients
{
ClientList.Add( ListenSocket.Accept() );
}
for each( Socket s in ClientList )
{
int recvValue;
if( (recvValue = s.Recv( data )) > 0 )
{
//process command
}
else
{
if( recvValue == 0 ) //client has quit
{
s.Close();
ClientList.Remove( s );
}
else
{
// process error
}
}
}
} |
|
|
|
|
|
#8 |
|
Programmer
Join Date: Jun 2005
Posts: 92
Rep Power: 4
![]() |
@jayme: you can't set the return value of recv, the function determines that. Recv( is specific to a certain socket, so if the user closes the program then recv will always fail, so you need to close that socket and reinitilize it with the listen and accept functions. What you need to do is place a while(1) before your call to the listen function, and end the loop after your do ... while that receives data from the user. Then, instead of returning 1 when recv( fails, close the socket and then put continue;, so you can go to the top of the loop and listen for another user. Then the program continues as normal.
|
|
|
|
|
|
#9 | |
|
Professional Programmer
|
ahh.. Well then i was trying to put a loop in the wrong area.. thanks
__________________
▄▄▄▄ Quote:
Due to incorrect calculations during the middle ages, our calendar actually begins a few years after Jesus' birth. Thus the real 6/6/6 happened a few years back. The world already ended and you missed it. Download Code::Blocks now! ▄▄▄▄ |
|
|
|
|
|
|
#10 |
|
Newbie
Join Date: Sep 2005
Posts: 28
Rep Power: 0
![]() |
It very common to handle every incoming connection to the server, not in the parent process, but with child processes using
fork(); If you're programming under windows though, I don't know if you have a POSIX-like environment that supports these system calls...
__________________
The geeks shall inherit the earth. |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|