Thread: Socketing

    #31
  1. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    Originally Posted by miz6565
    And to make other people talk to my server, do I have to set up a network for that? I don't know why but it's been stressing in my head.
    Actually, yes you would need to.

    One option would be to set up a DMZ behind your firewall and place a dedicated server there. That would get your server out on the Internet. That would also make your server a target for any hacker out there, which is a reason for why that setup is called a DMZ ("demilitarized zone", which in Viet Nam is where most of the bloodiest fighting seemed to be). Before you would do that, you would want to make your server app as completely hacker-proof as you can, which is a very daunting task. So don't rush this option yet. It'll take you a while to be up to the task. Though in the meantime you can start to do some research.

    I remember hearing about computer gaming parties, over-nighters where everybody brought their computers to hook up in a dedicated LAN. The party usually started with a "crimping bee" where you'd make your own Cat-5 cables. This should be feasible and fairly safe and secure, though it would require you to all be co-located (ie, in the same place).

    You could look into Virtual Private Networks (VPN) which allow remote computers appear to be on the local network, though that's mainly a commercial option that might be outside your financial means.

    In the meantime, if you have extra computers you could put them on your LAN behind your firewall and experiment with them. Start small and build up from there.
  2. #32
  3. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Ok, I'm going to be reading your textual insights on the Application Layer later. Probably tonight if I get a chance. I wasn't thinking of making a network whatsoever (yet). Like I said, it was just in my mind.

    Anyway, I think you forgot to answer my last question. To make my server, I'll use your client. Same thing? 127.0.0.1:7 is what I should define for my structure? And if I wanted to use my client (which by the way I'm sure I fixed the bug since it worked twice without exiting) what would I do? Same thing as I would do with your client?
  4. #33
  5. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    Msg #29:
    Originally Posted by DWise1
    Originally Posted by miz6565
    To test my TCP server I'm going to make, I'll use your TCP client. Do I do the same thing? Run the executable like I did with the server?
    Normally, I would say that once you have your client working with a known-good server, then you should be able to use your own client in designing the server. However, your client still has a few problems, so I would have to recommend using mine in the meantime.
    So the basic principle is to use a client that you know works. You could even use the telnet client to connect to a tcp echo server, though I don't think that Win7 provides it by default.

    However, since you are writing the server then you are no longer obliged to use port 7. The only reason why you needed to use port 7 when developing the client was because a standard echo server would be bound to that port. Now that you are writing the server, you could use any port you want. If you do, then I would advise that you use a port number in the range of 49152 through 65535.

    Actually, since you ended up having to use my server, you could have used a port different from 7, just so long as you told the client to use the same port.

    And, yes, you would be connecting on localhost, which is 127.0.0.1.
  6. #34
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Wait, I have one question I thought I already knew.

    As I was making my server (btw which is looking good, it already connects to my client) I was thinking of using the function htonl because I wanted the parameter to be 50004 for the port to use. When I used htonl it was connectionless and I had to go back to htons to make it work.

    The question I'm asking is what's the difference between htons and htonl? I thought it was how much numbers it could hold; htons holding numbers up to 36667 (or whatever the max is for a short data type) and htonl for using long numbers.

    Can you please explain the difference?
  8. #35
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    Both function names are abbreviations for what they do:
    htons means "host to network, short int"
    htonl means "host to network, long int"

    From winsock2.h (look it up yourself in your compiler's INCLUDE directory):
    Code:
    typedef unsigned char	u_char;
    typedef unsigned short	u_short;
    typedef unsigned int	u_int;
    typedef unsigned long	u_long;
     . . . 
    
    struct sockaddr_in {
    	short	sin_family;
    	u_short	sin_port;
    	struct	in_addr sin_addr;
    	char	sin_zero[8];
    };
    sin_port is an unsigned short int.

    From limits.h, which specifies the maximum and minimum values of the various datatypes (again, look it up yourself in your compiler's INCLUDE directory):
    Code:
    /*
     * Maximum and minimum values for ints.
     */
    #define INT_MAX		2147483647
    #define INT_MIN		(-INT_MAX-1)
    
    #define UINT_MAX	0xffffffff
    
    /*
     * Maximum and minimum values for shorts.
     */
    #define SHRT_MAX	32767
    #define SHRT_MIN	(-SHRT_MAX-1)
    
    #define USHRT_MAX	0xffff
    
    /*
     * Maximum and minimum values for longs and unsigned longs.
     *
     * TODO: This is not correct for Alphas, which have 64 bit longs.
     */
    #define LONG_MAX	2147483647L
    
    #define LONG_MIN	(-LONG_MAX-1)
    
    #define ULONG_MAX	0xffffffffUL
    Using Windows' calc program:
    0xffff = 65535
    0xffffffffUL (the UL means "unsigned long") = 4294967295

    Ports number from 0 to 65535, which is the entire range of values for an unsigned short int. sin_port is declared to be an unsigned short int.

    Therefore, you need to use htons with the port, not htonl.

    Besides, we don't know how either function does its job. I suspect that it tests whether the local system is big- or little-endian and if it's little-endian then it swaps the bytes around. In that swapping, htons assumes that it should swap the two bytes (the sizeof of a short) while htonl assumes that it should swap the four bytes (the sizeof of a long). Those functions make those assumptions because C assumes that you, the programmer, know what you are doing. If you chose to use htonl, then you must actually want it to swap around four bytes instead of 2.

    BTW, the size of int is implementation dependent, which means that it can be different on different systems. In 16-systems, int was 16 bits long, same as a short int, but on 32-bit systems it's 32 bits long, same as a long int.
  10. #36
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    HEY! I got my tcp server to work :D

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<WinSock2.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    void Terminate(char *message)
    {
    	puts(message);
    	getchar();
    	exit(1);
    }
    
    int main(void)
    {
    	WSADATA wsd;
    	SOCKET TCPserver,TCPclient;
    	struct sockaddr_in server_info;
    	struct sockaddr_in client_info;
    	char buffer[100];
    	int size;
    	int re,se;
    	if(WSAStartup(MAKEWORD(2,0),&wsd) != 0)
    	{
    		Terminate("Unable to load functions");
    	}
    	if((TCPserver = socket(AF_INET,SOCK_STREAM,0)) == -1)
    	{
    		WSACleanup();
    		Terminate("Socket unable to load socket");
    	}
    	server_info.sin_port = htons(54007);
    	server_info.sin_family = AF_INET;
    	server_info.sin_addr.s_addr = htonl(ADDR_ANY);
    	if(bind(TCPserver,(struct sockaddr *)&server_info,sizeof(server_info)) == -1)
    	{
    		closesocket(TCPserver);
    		WSACleanup();
    		Terminate("Unable to bind");
    	}
    	listen(TCPserver,5);
    	puts("Listening for a connection...\n");
    	RECONNECT:                                                    //GOTO STATEMENT
    	size = sizeof(client_info);
    	if((TCPclient = accept(TCPserver,(struct sockaddr *)&client_info,&size)) == -1)
    	{
    		closesocket(TCPserver);
    		WSACleanup();
    		Terminate("Unable to accept anymore");
    	}
    	puts("Connected to client..\n");
    	while(1)
    	{
    		re = recv(TCPclient,buffer,100,0);
    		if(re == -1)
    		{
    			closesocket(TCPserver);
    			WSACleanup();
    			Terminate("Done recieving.");
    		}
    		else if(re == 0)
    		{
    			puts("Connection closed..\n");
    			goto RECONNECT;
    		}
    		else if(strlen(buffer) > 100)
    		{
    			closesocket(TCPserver);
    			WSACleanup();
    			Terminate("Something wrong with the program. Abort loop");
    		}
    		se = send(TCPclient,buffer,strlen(buffer),0);
    		if(se == -1)
    		{
    			closesocket(TCPserver);
    			WSACleanup();
    			Terminate("Unable to send");
    		}
    		memset(buffer,0,100);
    	}
    }
    I know using a goto statement is bad strategy. That was my mistake and I might fix it later.

    Anyways other than that what do ya think? Took me 3 hours to debug it (mainly because it took 5 minutes just for the programs to load).


    And I have a few questions. Questions I wasn't able to do.

    1. With your program you actually say the client's IP address. I'm asking how do you do that if you don't know there host name or their IP address (if I wanted to connect someone by the network).

    2. Should I move on to UDP protocol now?

    After UDP is that where network programming comes?
  12. #37
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    Taking a casual look (just came back from the ophthamologist and my pupils are still very dilated), the only complaint I would have is that if any of the sockets functions fail, you don't know what happened nor why they failed. That is what the Winsock function WSAGetLastError() is for. Yes, you'll just get a numeric code, but then you can look it up. Of course, you can only call it while the Winsock DLL is loaded, so you would need to call it before you call WSACleanup() and you could not use it to report the failure of WSAStartup(). Having a reason for the failure of a sockets function takes a lot of the guesswork out of debugging.

    Also, you aren't quite handling the shutdown of the connection gracefully, but that can come later. This is a first step, just getting a server to work. There's much more to learn, so you aren't really done yet, but all in good time.

    Other things you will need to learn for a tcp server include how to handle multiple clients, how to allow the server to do other tasks while waiting for a connection or to recv from a client, and how to shutdown gracefully.

    Part of the "graceful shutdown problem" is that the server could be in the middle of servicing a client request when the client suddenly sends a shutdown. What the server is expected to do is to finish sending all pending data to the client first and then it can also call shutdown(). Remember, the argument you pass to shutdown() signals whether you are done sending and/or receiving data, so when the client shuts down saying that it's done sending, it's still ready to receive more data until the server also signals that it's done sending.

    Your other questions:
    Originally Posted by miz6565
    1. With your program you actually say the client's IP address. I'm asking how do you do that if you don't know there host name or their IP address (if I wanted to connect someone by the network).
    Look at your accept() call. One of the arguments is &client_info, a pointer to a sockaddr_in. When accept() returns with a connection, the address information of the client that just connected is contained within client_info. That is how we know the address of who connected. Then if you want to know the domain name as well, you can use the DNS functions (see http://pgm.dwise1.net/sockets/dns.html).

    Originally Posted by miz6565
    2. Should I move on to UDP protocol now?
    Yes, that would be a good progression.

    BTW, in UDP you learn what client sent you that datagram through arguments in the recvfrom() function, somewhat like with the accept() function in TCP.
  14. #38
  15. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    ADDENDUM:

    Originally Posted by miz6565
    1. With your program you actually say the client's IP address. I'm asking how do you do that if you don't know there host name or their IP address (if I wanted to connect someone by the network).
    As I already said, that information is returned to you by accept() in your client_info struct and is similarly returned to you by recvfrom using the UDP protocol.

    But if you missed those and all you have is a socket that's connected (ie, there's a computer on either end, such as when a tcp client is connected to a tcp server), then you can get the IP and port address of either end of the socket. In the "Connect to a Server" section on my site at http://pgm.dwise1.net/sockets/sockets.html#GETSOCKNAME are the two functions, getsockname() and getpeername():
    Originally Posted by DWise1's Sockets Programming Pages

    getsockname()
    Get a local socket's address information

    #include "sys/socket.h"

    int getsockname(int socket, struct sockaddr *localAddress, int addressLength);


    - socket -- Socket (returned from socket())
    - localAddress -- sockaddr structure to receive local address
    - addressLength -- Number of bytes in the localAddress structure

    On success, getsockname() returns zero.
    On failure, it returns -1.



    getpeername()
    Get the remote peer's address information

    #include "sys/socket.h"

    int getpeername(int socket, struct sockaddr *peerAddress, int addressLength);


    - socket -- Socket (returned from socket())
    - peerAddress -- sockaddr structure to receive peer address
    - addressLength -- Number of bytes in the peerAddress structure

    On success, getpeername() returns zero.
    On failure, it returns -1.
    But it's still much easier to just save that IP address when you get it from accept() or from recvfrom().
  16. #39
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Other things you will need to learn for a tcp server include how to handle multiple clients

    In my book it says to handle multiple clients you'll need to fork them to the parent process. But Fork isn't allowed in windows.

    and how to shutdown gracefully.
    I'm a little edgy here. It does shutdown great. I know what you said that the server also has to be done sending it's packets but Why? Shouldn't the server just accept the client doesn't want to talk anymore and just do what it does, Wait for another client???
  18. #40
  19. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    Originally Posted by miz6565
    In my book it says to handle multiple clients you'll need to fork them to the parent process. But Fork isn't allowed in windows.
    The first sentence is not completely true, since forking is only one of at least four ways of handling the situation under UNIX/Linux. True, forking is a common approach to take, since forking is practically a life-style for programmers under UNIX, but it is not the only way.

    The second sentence is true. Forking is how UNIX implements multiprocessing, having a process spawn another process and communicate with it. You can also do that under Windows, but it's not as well known or used as forking is under UNIX/Linux. Rather, under Windows you would instead use one or more of the three other techniques available under UNIX/Linux.

    Those three techniques are:
    1. select
    2. non-blocking sockets
    3. multithreading.

    I discuss them on my page, Dealing With and Getting Around Blocking Sockets. I consider it a more advanced topic that you shouldn't delve into too deeply early one before you have worked out and have become thoroughly familiar and comfortable with the basics of both tcp and udp.


    Originally Posted by miz6565
    Originally Posted by DWise1
    and how to shutdown gracefully.
    I'm a little edgy here. It does shutdown great. I know what you said that the server also has to be done sending it's packets but Why? Shouldn't the server just accept the client doesn't want to talk anymore and just do what it does, Wait for another client???
    Why does the server need to be done sending its packets? Because of the entire purpose, the raison d'Ítre, of TCP: the quaranteed delivery of data.

    Also, by calling shutdown with the argument indicating that he has finished sending, the client is not indicating that he doesn't want the rest of his data! He has shut down sending, but not receiving. He still wants his data!

    You're familiar with FedEx and UPS, right? The customer prepares a packet that contains a request for a reply and he sends it. He's done sending, but does that mean that he no longer wants that reply? No, obviously not!

    OK, that analogy applies more to UDP datagrams than to TCP streams, so here's a real-life scenario based on HTTP. In older versions of HTTP, the TCP connection would only be opened to service a single request, at the end of which the connection would be closed; further requests to the same server required a new TCP connection. Now you can specifiy that you want to keep the connection open, though you also still have the option of doing it the old way.

    Here's the scenario: an HTTP client (eg, your web browser) connects to an HTTP server (AKA "web server"), requests one HTML file (AKA "a web page") and immediately calls shutdown(1) to disallow further sends from the client. You are arguing that that means that the client does not want to receive that web page it just requested. Your argument is obviously not true, because that client obviously does want to receive what it had requested. All it has done with that shutdown(1) call is to tell the server that this is the last request, so when the server is done servicing that request then it is free to shutdown its own end of the connection.

    That is why the graceful shutdown is so important. Ill-behaved network applications cause bad things to happen, such as the loss of data. We need for our network applications to be well-behaved.

    Again, I discuss the graceful shutdown at http://pgm.dwise1.net/sockets/tcp_ip.html#SHUTDOWN. Also other reading on the subject, courtesy of Google (3 out of 122,000 hits):

    http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx

    http://stackoverflow.com/questions/5...n-a-tcp-socket

    http://stackoverflow.com/questions/8...e-a-tcp-socket
  20. #41
  21. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Finished my UDP client, it was very easy to make.

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<WinSock2.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    void Terminate(char *message);
    
    int main(void)
    {
    	WSADATA wsd;
    	SOCKET server;
    	struct sockaddr_in server_info;
    	int size;
    	char buffer[100];
    	if(WSAStartup(MAKEWORD(2,0),&wsd) != 0)
    	{
    		Terminate("Unable to start up functions");
    	}
    	if((server = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    	{
    		Terminate("Unable to start up socket");
    	}
    	server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
    	server_info.sin_port = htons(7);
    	server_info.sin_family = AF_INET;
    	size = sizeof(server_info);
    	puts("You're able to start sending data. Start chatting with the server");
    	while(1)
    	{
    		fgets(buffer,100,stdin);
    		if(sendto(server,buffer,strlen(buffer),0,(struct sockaddr *)&server_info,size) == -1)
    		{
    			closesocket(server);
    			Terminate("Not able to send. Goodbye");
    		}
    		memset(buffer,0,100);
    		if(recvfrom(server,buffer,100,0,(struct sockaddr *)&server_info,&size) == -1)
    		{
    			closesocket(server);
    			Terminate("Not able to recieve. Goodbye");
    		}
    		puts(buffer);
    		printf("\n");
    		memset(buffer,0,100);
    	}
    	getchar();
    	return 0;
    }
    
    void Terminate(char *message)
    {
    	puts(message);
    	puts(strerror(WSAGetLastError()));
    	WSACleanup();
    	getchar();
    	exit(1);
    }
    The only thing I have to ask is did I even need to close the socket or shutdown? It says in your website I didn't have to but just want to make sure just in case I'm not mistaken anything. Plus, whenever I typed up something it would always say handling client IP address, which I expected.

    The only thing I didn't expect was you know how UDP is unreliable? I typed up many many words and the server always got the input and wrote back to me. How come I didn't get one data send that was lost?

    UDP server, here I come! :trockon:
  22. #42
  23. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Finished my UDP server. Please check both my programs out and tell me what you think of them. You are guiding me towards socket programming and I thank you because of that.

    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<WinSock2.h>
    //59023
    #pragma comment(lib,"ws2_32.lib")
    
    void Terminate(char *message);
    
    int main(void)
    {
    	WSADATA wsd;
    	SOCKET server,client;
    	struct sockaddr_in server_info;
    	struct sockaddr_in client_info;
    	int size;
    	char buffer[100];
    	if(WSAStartup(MAKEWORD(2,0),&wsd) != 0)
    	{
    		Terminate("Unable to load functions");
    	}
    	if((server = socket(AF_INET,SOCK_DGRAM,0)) < 0)
    	{
    		Terminate("Unable to load socket");
    	}
    	server_info.sin_port = htons(59023);
    	server_info.sin_family = AF_INET;
    	server_info.sin_addr.s_addr = ADDR_ANY;
    	if(bind(server,(struct sockaddr *)&server_info,sizeof(server_info)) == -1)
    	{
    		closesocket(server);
    		Terminate("Unable to bind");
    	}
    	puts("Server is ready to go\n");
    	while(1)
    	{
    		memset(buffer,0,100);
    		size = sizeof(client_info);
    		if(recvfrom(client,buffer,100,0,(struct sockaddr *)&client_info,&size) == -1)
    		{
    			closesocket(server);
    			Terminate("Done reading. Goodbye");
    		}
    		if(sendto(client,buffer,100,0,(struct sockaddr *)&client_info,size) == -1)
    		{
    			closesocket(server);
    			Terminate("Done sending. Goodbye");
    		}
    	}
    	getchar();
    	return 0;
    }
    
    void Terminate(char *message)
    {
    	puts(message);
    	puts(strerror(WSAGetLastError()));
    	WSACleanup();
    	getchar();
    	exit(1);
    }
    I just wanted to tell you just in case I did something wrong (meaning I didn't get something) I used a while loop on both the programs because UDP doesn't need a graceful shutdown. Would of been the same if it's TCP.

    I'm going to learn how to implement a graceful shutdown after you check out both my programs and say it's alright (just to make sure I'm making progress.)

    Graceful shutdown

    mutliply clients

    Great socket programmer :D
  24. #43
  25. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,311
    Rep Power
    2223
    I hadn't come across strerror() before. The problem is that it only knows about OS errors and nothing about Winsock errors. So to test that, I took the first Winsock error code listed at [ur]http://msdn.microsoft.com/en-us/library/aa924071.aspx[/url]:
    10004, WSAEINTR
    Interrupted function call. This error is returned when a socket is closed or a process is terminated, on a pending Winsock operation for that socket.
    I added this line to your server program:
    puts(strerror(10004));
    This is what it displayed:
    Unknown error
    That means that strerror knows nothing about the Winsock error codes. Which means that your attempted use of it to display information about Winsock errors does not work. You need to try something different. At the very least, you need to display the error number so that you can look it up at the MicroSoft Developers Network (MSDN) web page I just gave you.
  26. #44
  27. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Alright. That's an easy fix.

    Anything else you have to say about the programs before I read on a graceful shutdown?
  28. #45
  29. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    The typical manner in which to rudely "slam the connection shut" is by calling close() / close_socket() without first having called shutdown(1) and waited to detect (via recv() returning a zero) the peer's own shutdown.
    My only problem was I forgot to call shutdown on both the client and the server? I only there are many approaches to shutting down gracefully but if I did it this way I just had to call shutdown before closing the socket

IMN logo majestic logo threadwatch logo seochat tools logo