Thread: Socketing

Page 1 of 4 123 ... Last
  • Jump to page:
    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0

    Socketing


    I'm trying to learn something new. Kinda complicated but I like learning new things. Makes me excited with joy :D

    Code:
    #include<stdio.h>
    #include<WinSock.h>
    #include<WinSock2.h>
    
    int main()
    {
    	int stats;
    	if(stats = socket(AF_INET,SOCK_STREAM,0) < 0)
    	{
    		puts("socket() fail");
    	}
    	else
    	{
    		puts("sweet");
    	}
    	printf("%d",stats);
    	getchar();
    	return 0;
    }
    Can anyone tell me why this doesn't print a number? All it prints in the output is

    Initialising Winsock...Initiliased
    Socket Created.
    Connected
    Data Send

    and exits. Is the program in control while this is happening?
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    Welcome to the Wonderful World of Sockets! It's actually easier than it looks, though it can look very intimidating. My write-up starts at http://pgm.dwise1.net/sockets/index.html, where I include basic TCP/IP theory (especially the difference between tcp and udp) along with descriptions of the sockets functions, basic descriptions of sessions, and discussions of various topics, along with a few examples with source code.

    Sockets were created for BSD UNIX and most discussions of sockets programming tend to be UNIX-specific. Sockets were adapted for Windows as WinSock. Most UNIX sockets functions are supported by WinSock, though there are some differences that you need to be aware of. I discuss that on my page, DWise1's Page on Converting Sockets Programming to WinSock. Please bear in mind that I wrote that in 2003, so the samples are geared towards Visual C++ 6, but they should translate easily to later versions of Visual Studio and to other compilers.

    The first problem that I see with your code is that it does not in the least bit match the output that you claim to get. Nonetheless, I will address the code that you are showing us instead of the code that you actually ran to get that output.

    UNIX/Linux sockets support is built into the operating system itself, whereas WinSock sockets support is provided in a dynamically linked library file, a DLL. When using WinSock, you need to load and initialize that DLL before you can call any sockets function, and you must close that DLL and clean up after it at the end. You must also link in the static WinSock library which enables you to use the DLL; with Winsock2, that would be ws2_32.lib (or .a if you're using MinGW gcc).

    Also, you only need to #include winsock2.h. You do not need to also #include winsock.h.

    Here's a code fragment for initializing the Winsock DLL:
    Code:
        WORD wVersionRequested;          /* Version of Winsock to load */
        WSADATA wsaData;                 /* Winsock implementation details */ 
    
    
        /* Winsock DLL and library initialization  */
        wVersionRequested = MAKEWORD(2, 0);   /* Request Winsock v2.0 */
        if (WSAStartup(wVersionRequested, &wsaData) != 0) /* Load Winsock DLL */
        {
            fprintf(stderr,"WSAStartup() failed");
            exit(1);
        }
    After you have successfully run WSAStartup, then you can call socket().

    And when you are done, you are expected to call:
    Code:
        /* Clean up Winsock */
        WSACleanup();
    PS
    While many things are the same between BSD sockets and Winsock, there are also important differences that you must be aware of. I tried to cover all the important ones on my Winsock page linked to above.

    A very valuable resource is the Winsock Programmer's FAQ. I link to it from my page, as well as from here.
    Last edited by dwise1_aol; June 12th, 2013 at 02:40 PM.
  4. #3
  5. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,417
    Rep Power
    1871
    Initialising Winsock...Initiliased
    Socket Created.
    Connected
    Data Send
    But none of these strings are in your test code.

    > if(stats = socket(AF_INET,SOCK_STREAM,0) < 0)
    Beware of operator precedence.
    You created a socket, compared it with zero (using <), in the process threw away the actual socket ID, and then assigned stats the boolean result of the comparison (basically either 0 or 1).

    You've written this.
    if(stats = (socket(AF_INET,SOCK_STREAM,0) < 0))

    You want to write this.
    if((stats = socket(AF_INET,SOCK_STREAM,0)) < 0)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  6. #4
  7. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Wow, socket programming is FUN! I actually really like it. And trust me, I haven't thought this much in ages :D
    Anyway I have a feeling learning socket programming might take a bit, so I'ma just post my questions/comments on this forum. Alright with you guys?

    Anyway, I have a question. Not a code to be debugged, but a question.

    While I was doing some research about binding a port (where I'm at right now), I learned something new. A way the computer handles bytes. The Big endian and Little endian way. I find these two ways of sorting bytes VERY interesting. But can someone tell me the advantages and disadvantages of little endian? Why would computers use it that way?
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    Some people are tall, some are short. Some people are right-handed, some are left-handed. That's just how they are.

    Some computers are big-endian, some are little-endian. As far are we're concerned, that's just how they are. It's a fact that we need to recognize and be able to deal with when we pass data from any possible computer to any other possible computer in the world, which is basically what networking is about. And as I describe in my Byte Order section, sockets provides functions for converting short and long ints between network byte order (ie, big-endian) and host byte order (who knows which is it?).

    As for why some are big-endian and some are little-endian, that was a design decision made by the engineers who designed the processor. And once that design decision was made, then all subsequent processors in the same processor family needed to comply with that original design decision. To assess the advantages and disadvantages of one endianness over the other, you would need to get deeply immersed in the actual digital electronics and the digital circuit designs that move and organize bytes of data. That is way beyond the scope of this forum. Suffice to say that a design engineer with knowledge of such things made a decision and that's the way it is now. Also bear in mind that what a human would find convenient because of what he had been taught and has used all his life has virtually no bearing on how a computer might work most efficiently; that kind of thinking led early inventors to try to create aircraft with wings that would flap, all of which failed.

    Anyway, Intel processors are one example of little-endian machines. We never notice it until we need to share binary data with big-endian devices.

    PS

    I was thinking of some advice to impart. Sockets programming is really the simple part of network programming. All it does is form the connection between the two hosts and transfers data between them. Basically, once you have written code to resolve addresses (ie, domain name to IP address and vice versa), then you don't have to write it again but instead can reuse the same code over and over again. Same thing for the code to connect to a server. And for the code to disconnect and shut down the connection gracefully. And for sending a packet and receiving a packet. Once you have learned to do those things, most of your subsequent projects will just reuse that code with only minor modifications.

    The hard part and the really exciting part is on the application level. That is where you will need to design the format of the data packets (all tcp or udp does is move the packets in blissful ignorance of their contents) and to design the manner in which the client and the server will communicate with each other in order to conduct a useful session -- that is called a protocol. That is where the real work and the creativity and the excitement lies!

    You might also want to get a packet sniffer for when you get serious about this. I use WireShark, which is free. What a packet sniffer does is that it looks at the packets on a network and captures them for you to examine. From the GUI, it appears to have been written for Linux and ported to Windows.
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Well first I'm going to take it one day at a time. I probably won't get more in-depth in network programming until later years, maybe when I'm in high school. Right now I'm trying to learn the basics so later I won't struggle or I can start on a different path.

    Thanks for the advice. Anyway, can you help me out with this program dwise1_aol? I've been working on it for about 45 minutes and I'm getting no where.

    Code:
    #include<stdio.h>
    #include<WinSock2.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    int main()
    {
    	WSADATA wsd;
    	int s0cket;
    	int b;
    	struct sockaddr_in name;
    	if(WSAStartup(MAKEWORD(2,0),&wsd) == 0)
    	{
    		puts("Functions ready\n");
    	}
    	if(s0cket = socket(AF_INET,SOCK_STREAM,0) >= 0)
    	{
    		puts("Socket has a descripter. Descripter %d\n",s0cket);
    	}
    	name.sin_family = AF_INET;
    	name.sin_port = htons(0);
    	name.sin_addr.s_addr = htonl(INADDR_ANY);
    	if(b = bind(s0cket,(struct sockaddr *)&name,sizeof(name)) == -1)
    	{
    		puts("Won't bind");
    	}
    	puts("hi"); //wait for program to end. Just in case it loads slow
    	WSACleanup();
    	getchar();
    	return 0;
    }
    My problem is the binding part. I don't know why but it always returns -1. I've looked it up and I have the right syntax. I get no errors when I print out perror(). I don't know what is up and like I said, getting no where. Why can't I get an open port for my socket?
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    How can you tell that bind always returns a -1? You never display that value.

    Look at your if statement:
    if(b = bind(s0cket,(struct sockaddr *)&name,sizeof(name)) == -1)
    What exactly are you testing there? Remember, equality (==) has higher precedence than assignment (=) and so will be done first. Here, I'll explain it. You call bind(). You immediately test that return value with -1, which will give you either zero for false or non-zero for true. Then you take that zero or non-zero and assign it to b. The value of the entire expression is the value assigned to b. Now while that just happens to do what you wanted, it's still horribly frakked up. Normally what you would want to do is to assign the return value to a variable and then test it. For that, you would need to use parentheses to override the normal precedence. This is what you would want to write:
    if((b = bind(s0cket,(struct sockaddr *)&name,sizeof(name))) == -1)

    My next question is: What actual output did you get? How did the preceding operations (ie, WSAStartup and socket) fare?

    Well, looking at the socket() call, I see you making the exact same mistake:
    if(s0cket = socket(AF_INET,SOCK_STREAM,0) >= 0)
    Let us assume that the non-zero value that the comparison operator returns is one (1). You create a socket and test whether it's >= 0. Let's assume that socket was successful and returned a value of 4. 4>=0 is true, so that evaluates to 1. So you assign that 1 to s0cket. Not the 4 which is the socket's actual handle (UNIX uses file descriptors; Winsock uses HANDLEs -- it just happens to work even when you confuse the two concepts), but rather the one which is the result of that >= test. So then you try to bind File 1 to a socket port. First, in Windows you cannot treat a socket as if it were a file. Second, 1 is already taken, by the standard output file, stdout. You cannot bind the monitor display output to a socket port!

    What you need to do is to assign the return value of socket to s0cket, and then after you do that you can test if for being >=0. You need to use parentheses in the manner that I have already shown you above.

    Come to think of it, recently somebody here (I think either salem or ptr2void) had to correct somebody who had made that exact same stupid mistake. Was that you? I think that was you. Didn't you learn the first time?

    Also, if any part of that chain of operations fails, then you should not try to continue anyway. If Winsock won't start up, then nothing else will work. If a socket fails to be created, then anything you try to do with it will also fail. If any of those steps fail, then you need to handle that failure, usually by reporting the failure and terminating the program. Here's some code from my tcp server example to illustrate that point:
    Code:
        /* Winsock DLL and library initialization  */
        wVersionRequested = MAKEWORD(2, 0);   /* Request Winsock v2.0 */
        if (WSAStartup(wVersionRequested, &wsaData) != 0) /* Load Winsock DLL */
        {
            fprintf(stderr,"WSAStartup() failed");
            exit(1);
        }
    
    /* 1. Create a socket.  */
        /* Create socket for incoming connections */
        if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
            DieWithError("socket() failed");  // displays error message and exits
    
    /* 2. Bind the socket to a specific port with the bind() function.  */
        /* First we construct local address structure containing that port we will bind to*/
        memset(&echoServAddr, 0, sizeof(echoServAddr));   /* Zero out structure */
        echoServAddr.sin_family = AF_INET;                /* Internet address family */
        echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
        echoServAddr.sin_port = htons(echoServPort);      /* Local port */
    
        /* Then we perform the actual binding operation */
        if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
            DieWithError("bind() failed");  // displays error message and exits
    Please note my socket() call.

    Comments on this post

    • salem agrees : Already told them about precedence, it didn't work - hope your post succeeds.
  14. #8
  15. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Ok, now I'm onto connecting the sockets. I want to ask something regardless if you have any comments to say (which are really helpful).

    Code:
    #include<stdio.h>
    #include<WinSock2.h> //Version 2 functions
    #include<string.h>
    #include<errno.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    int main(void)
    {
    	WSADATA wsd;
    	int s0cket,s0cket2; //s0cket for local socket, s0cket2 for remote socket
    	int b,b2,c; //b and b2 for binding,c for connecting
    	struct sockaddr_in name;
    	struct sockaddr_in r3mote;
    	if(WSAStartup(MAKEWORD(2,0),&wsd) == 0)
    	{
    		puts("Functions are ready to be activated\n");
    	}//if statement to initiliase the winsock functions
    	if((s0cket = socket(AF_INET,SOCK_STREAM,0)) >= 0)
    	{
    		printf("Socket descriptor1 :%d\n",s0cket);
    	}
    	if((s0cket2 = socket(AF_INET,SOCK_STREAM,0)) >= 0)
    	{
    		printf("Socket descripter2 :%d\n",s0cket2);
    	}//add s0cket and s0cket2 to data stream
    	name.sin_family = AF_INET;
    	name.sin_port = htons(0);//kernal chooses
    	name.sin_addr.s_addr = INADDR_ANY;
    	r3mote.sin_family = AF_INET;
    	r3mote.sin_port = htons(0);//kernal chooses again
    	r3mote.sin_addr.s_addr = inet_addr("127.0.0.01"); 
    	if((b = bind(s0cket,(struct sockaddr *)&name,sizeof(name))) == 0)
    	{
    		puts("Bind worked\n");
    	}
    	if((b2 = bind(s0cket2,(struct sockaddr *)&r3mote,sizeof(r3mote))) == 0)
    	{
    		puts("Bind worked again!\n");
    	}
    	if((c = connect(s0cket2,(struct sockaddr *)&r3mote,sizeof(r3mote))) != 0)
    	{
    		puts(strerror(errno));
    	}
    	puts("Ready for next activity");
    	getchar();
    	return 0;
    /* I use 127.0.0.01 IP so I can talk to a machine when this code is all down without making a network.*/
    }
    When you connect to a server is it better to use the accept or connect function? I've been trying to get this connect function to work for hours and I haven't had any good solutions. I think my problem is connect's first argument takes a SOCKET data type and I have an integer there. But I'm not sure because it doesn't print an error. Would you choose accept or connect?

    and I wanted to ask, the tutorial I'm using (the one that uses the connect function) says that binding can be optional for client side but mandatory for server side. Why is it optional for client side and what improvements does it take if I do bind it on the client side?
  16. #9
  17. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    Originally Posted by miz6565
    I think my problem is connect's first argument takes a SOCKET data type and I have an integer there.
    Your problem is with the port number, but let's discuss a few things first.

    In UNIX/Linux, almost everything is a file. Every file is accessed through its file descriptor which is an int. For example, the file descriptors for standard input (stdin), standard output (stdout), and standard error output (stderr) are 0, 1, and 2, respectively.

    In Windows, almost everything is an object. Every object is accessed through it handle, or rather HANDLE (I'm not shouting; it is capitalized in C). A HANDLE is normally typedef'd as unsigned int, though that can vary between compilers. So a HANDLE is a unique number that the system gives you when it creates an object so that you can use that unique number to access that specific object. A socket is an object and a SOCKET is a HANDLE to a socket object. Since SOCKET is typedef'd as unsigned int, you are indeed able to declare a socket to be int and it will still work.

    Same thing is true of several special datatypes in C, both in UNIX and in Windows. Most of those special datatypes (eg, time_t) are just int or unsigned int. The advantage of using the special datatype is that you clearly communicate what that variable is; also, the compiler can change the datatype to something else and you won't have to hunt through all your code to change everywhere you didn't use that special datatype. For example, UNIX time will no longer work past 2038, so in order to save UNIX time the typedef of time_t will have to change. When that happens, all the time variables you declared as time_t will recompile correctly with the fix. But not the ones you just declared as unsigned int; those you will need to hunt down and change by hand, missing a number of them in the process so your program will not work right.

    For the same reason, while you don't have to declare your sockets as SOCKET, it's better practice that you do.


    Originally Posted by miz6565
    When you connect to a server is it better to use the accept or connect function? I've been trying to get this connect function to work for hours and I haven't had any good solutions.
    Clients always connect. Servers always accept. Remember that cardinal rule always! Or at least until we have a good reason to violate it -- believe me, you won't be able to find a good reason until after you have mastered sockets programming, so simply follow the rule then learn why that rule exists.

    Please read my page on basic client/server application structure at http://pgm.dwise1.net/sockets/basic_apps.html]. It includes the communication sequence for both client and server placed side-by-side. I also describe a broadcast server/client application, which will help answer your questions about binding.

    I assume that the code you presented is for a client, mainly because you talk about it not being able to connect to a server. Did you also write the server yourself? I would recommend that you use a server that somebody else wrote. In Windows you can enable simple TCP/IP services such as echo (port 7). If the server isn't working, then even if you have a correctly running client it still won't work. Start with a working server in order to write a working client, then you can use that working client to write your own server.

    Also, the client only needs one socket.

    Originally Posted by miz6565
    and I wanted to ask, the tutorial I'm using (the one that uses the connect function) says that binding can be optional for client side but mandatory for server side. Why is it optional for client side and what improvements does it take if I do bind it on the client side?
    Yes, your tutorial is quite correct.

    The client and server communicate by sending each other packets. The data in the packet is what you're sending; think of it as simply being an array of bytes, of unsigned char. To that data packet, you attach headers containing information that TCP/IP will need to deliver that data packet and for the recipient to know what to do with it. The information of importance here is the address that you're sending the packet to and the address that sent it; that address includes both the IP address and the port number.

    OK, how does the server know the client's address in order to send responses to it? Well, when the client connects to the server, the packet it sends contains the client's address. When the server accepts (remember, clients connect but servers accept) the client's connect packet, accept() creates a new socket with the client's address (both IP and port) in it and returns it for the server to save in a socket variable.

    OK, so how does the client know the server's complete address in order send that very first packet to establish the connection? Ah! That is the problem, now isn't it? How does the client know? Because the client not only needs to know the IP address, but also the port number (and also whether it's udp or tcp). So how does the client know? I cover that in the Basic Client/Server Operation section of that page I just gave you to read; the link to that section is http://pgm.dwise1.net/sockets/basic_apps.html#BASIC_OPS. Here are a few short paragraphs from it:
    Basically, the server uses a specific, pre-determined port to wait for a client to contact it, whereupon the service is performed, the client ends the session, and the server goes back to waiting for a client to contact it.

    The idea of the predetermined port is that the client needs to know what port the server is listening on in order to contact the server.

    . . .

    Let's designate the two ends of the connection as the "listener" and the "sender." Basically, the listener socket binds to a specific port and waits to receive a message, either with the listen() function (tcp) or with a recvfrom() (udp). The reason it has to bind to a specific port is because the sender must specify which remote port he is going to try to connect to, so the sender must know ahead of time which port that is going to be. This is why the well-known ports are used so much and why they are each reserved for a specific service. That way, your client can connect to the desired service on any server.

    On the other hand, the sender does not need to bind to a specific port. When he connects to the listener, the OS automatically binds his socket to an unused port. Then that port number is included in the header of the packets he sends, so the listener is automatically told what port to send the response to. Nice and neat.
    And there you have your answer. Every single time the server runs, it needs to be listening on the one specific port. If you let the OS choose that port at random, how is the server ever to guarantee that it's listening on that one specific port. By binding to that on specific port! The recipient of the first packet needs to do this so that the sender can know where to send it; in almost all cases the recipient is the server and the client is the sender.

    However, there is a kind of application that in which the roles of client and server are reversed: the Broadcast Client/Server. This is where the server broadcasts a message to a specific port on all hosts on the network and whichever clients want to receive that broadcast must "listen" on that specific port -- this is a udp application, so listen() is not used. In this situation, it is the client who must bind to that specific port. Read about it by following that link.



    Now for your problem. First, I have to assume that the server binds to the port you want it to listen on with the listen() function. If it does not do that, then you have two problems instead of one.

    When you set up r3mote, you need to set the sin_port field to the port that the server has bound to. There are 65,536 different tcp ports. Your chances of accidentally getting the port that the server has bound to is one in 65,536, which is not good at all. Whenever you try to connect to a server, you want it to work each and every time. That means that you need to set the sin_port field to the port that the server is listening on.

    And don't try binding the port that the client is on. If it's already being used, I believe you'd get an error. I don't know for sure because I would never consider do something like that.
    Last edited by dwise1_aol; June 17th, 2013 at 07:17 PM.
  18. #10
  19. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    Alright. I see what you're saying, but I'm still stuck on the connecting part. (I've edited my code to make it look neater, more clear what I want to do and reliable.)

    Code:
    #include<stdio.h>
    #include<WinSock2.h>
    #include<string.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    int main(void)
    {
    	WSADATA wsd;
    	SOCKET client,server;
    	//struct sockaddr_in client_in;
    	struct sockaddr_in server_in;
    	int b,l,c;
    	if(WSAStartup(MAKEWORD(2,0),&wsd) == 0)
    	{
    		puts("Functions are enabled.\n");
    	}
    	if((client = socket(AF_INET,SOCK_STREAM,0)) >= 0)
    	{
    		printf("Client socket descriptor %d\n",client);
    	}
    	if((server = socket(AF_INET,SOCK_STREAM,0)) >= 0)
    	{
    		printf("Server socket descriptor %d\n",server);
    	}
    	server_in.sin_family = AF_INET;
    	server_in.sin_port = htons(80);//http protocol
    	server_in.sin_addr.s_addr = htonl(INADDR_ANY);
    	/*client_in.sin_family = AF_INET;
    	client_in.sin_port = htons(0); //kernal chooses port for ME
    	client_in.sin_addr.s_addr = htonl(inet_addr("127.0.0.01")); I just noticed this part is useless..*/
    	if((b = bind(server,(struct sockaddr *)&server_in,sizeof(server_in))) == 0)
    	{
    		puts("Binded the server\n");
    	}
    	if((l = listen(server,10)) == 0)
    	{
    		puts("Server has time to talk to you\n");
    	}
    	if((c = connect(client,(struct sockaddr *)&server_in,sizeof(server_in))) == 0)
    	{
    		puts("Client connected\n");
    	}
    	puts("Waiting to accept a connection...");
    	printf("%d\n",SOCKET_ERROR);
    	puts(strerror(SOCKET_ERROR));
    	getchar();
    	return 0;
    }
    My main source was your page, http://pgm.dwise1.net/sockets/sockets.html#CONNECT and I did what I said, use your peer socket address (last time I didn't) and I still couldn't connect to the server. What is wrong with this?
  20. #11
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    Is this a client or is it a server? It cannot be both!

    A client only needs one socket. All it needs to do to connect is to set up a sockaddr_in struct with the server's complete address (IP and port) and call connect. That's all!

    A server needs two sockets declared. The one socket is the listening socket which the server needs to create with socket() and then bind to a specific port, and then turned into a listening socket by passing it to listen(). The other socket will be assigned the handle for the client socket by the accept() call.

    You are trying to combine characteristics of both client and server apps into one. That will not work for a simple client/server application suite. So please make up your mind which this program is supposed to be.

    There is also the question about the server. Did you write it? Or is it a completely functional server? What kind of server is it?
  22. #12
  23. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    For an example of tcp client code, here's part of my tcp echo client example from my site:
    Code:
        /* Winsock DLL and library initialization  */
        wVersionRequested = MAKEWORD(2, 0);   /* Request Winsock v2.0 */
        if (WSAStartup(wVersionRequested, &wsaData) != 0) /* Load Winsock DLL */
        {
            fprintf(stderr,"WSAStartup() failed");
            exit(1);
        }
    
    /* 1. Create a socket. */
        /* Create a reliable, stream socket using TCP */
        if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
            DieWithError("socket() failed");
    
    /* 2. Connect to the server. */
        /* Construct the server address structure */
        memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
        echoServAddr.sin_family      = AF_INET;             /* Internet address family */
        echoServAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
        echoServAddr.sin_port        = htons(echoServPort); /* Server port */
    
        /* Establish the connection to the echo server */
        if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
            DieWithError("connect() failed");
        else
            printf("Connected to Server %s\n",servIP);
    
        /* connected, so perform the echo session */
        /* Will perform the calls to send(), recv(), shutdown, and close */
        ConductEchoSession(sock);
    
        /* Clean up Winsock */
        WSACleanup();  
    
        return 0;
    }
    
    
    /********************************************************/
    /* DieWithError                                         */
    /*    Separate function for handling errors             */
    /*    Reports an error and then terminates the program  */
    /********************************************************/
    void DieWithError(char *errorMessage)
    {
        ReportError(errorMessage);
        exit(1);
    }
    
    /**************************************************************************/
    /* ReportError                                                            */
    /*    Displays a message that reports the error                           */
    /*    Encapsulates the difference between UNIX and Winsock error handling */
    /* Winsock Note:                                                          */
    /*    WSAGetLastError() only returns the error code number without        */
    /*    explaining what it means.  A list of the Winsock error codes        */
    /*    is available from various sources, including Microsoft's            */
    /*    on-line developer's network library at                              */
    /*  http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx */
    /**************************************************************************/
    void ReportError(char *errorMessage)
    {
        fprintf(stderr,"%s: %d\n", errorMessage, WSAGetLastError());
    }
    One socket, one sockaddr_in. Call connect with that socket and that server sockaddr_in. A socket contains the addresses of both ends of the connection; you provide the server's end with that sockaddr_in and connect automatically provides your end. As you should have read in my section on connect(), you can use getsockname() to get your own address information and getpeername() to get the remote end's address information.

    Please note DieWithError(), which I got from a textbook. If there's an error, then report it and exit the program; if there's that severe of an error, then there is no use trying to proceed (eg, if socket() fails, then everything you will try to do with that socket will also fail). It uses the Winsock function, WSAGetLastError(), to get the Winsock error number. Those error codes are listed at the web site I gave in that comment block. Look up the code to see the reason for the error.

    And I still want to know what server you're trying to connect to.

    Also, there's a command-line utility that you should find helpful, netstat. You can use it to list all the open sockets on your system. I normally use netstat -an. Examples of what you could use it for would be to check that your server is listening for a connection, or checking that a client has connected to a server.
  24. #13
  25. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    OHHHHHHH, I was getting that mixed up :p
    I thought you write the client and server at the same time and IN THAT CODE you connect the client TO the server (from the first socket I made to another).

    Now I realize that making the client program is easy.. it only took me about an hour to make :cool: wanna see?

    Code:
     #include<stdio.h>
    #include<WinSock2.h>
    #include<string.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    int main(void)
    {
    	WSADATA wsd;
    	SOCKET server;
    	struct sockaddr_in server_info;
    	int c,s,r;
    	char *message;
    	char size[2000];
    	if(WSAStartup(MAKEWORD(2,0),&wsd) == 0)
    	{
    		puts("Functions initiliased\n");
    	}
    	if((server = socket(AF_INET,SOCK_STREAM,0)) == 0)
    	{
    		puts("Socket loaded\n");
    	}
    	server_info.sin_port = htons(80);
    	server_info.sin_family = AF_INET;
    	server_info.sin_addr.s_addr = inet_addr("74.125.235.20");
    	if((c = connect(server,(struct sockaddr *)&server_info,sizeof(server_info))) == 0)
    	{
    		puts("Connected\n");
    	}
    	message = "GET / HTTP/1.1\r\n\r\n";
    	if((s = send(server,message,strlen(message),0)) > 0)
    	{
    		puts("sent\n");
    	}
    	if((r = recv(server,size,2000,0)) > 0)
    	{
    		puts("recieved\n");
    	}
    	puts(size);
    	closesocket(server);
    	WSACleanup();
    	getchar();
    	return 0;
    }
    I'm still going to do a lot more testing but let me say dwise_1, thanks for CLEARING THAT UP.

    I just have one concern. Should I allocate memory when I call the recv function since I don't know how much data HTTP will send me? (you said that on your website).

    Also, how are you able to talk to the HTTP protocol? What I mean is I typed up that command (the message variable) and I found it on the internet. Are there any sources I can learn from to talk to HTTP?

    and if you have any comments to say, please do. I still have to read more but I'm getting somewhere :D
  26. #14
  27. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,255
    Rep Power
    2222
    While there are many complex ways you could design a networking application, first you need to learn how a single client works and how a single server works. After you have mastered those, you can move on to more complex designs.

    The first question I have is whether it did connect to the HTTP server. If it did, then that should have been a good feeling.

    One comment I still have is your lack of error handling. If WSAStartup fails, then none of the sockets functions can possibly work. So if WSAStartup fails, then socket() will fail. If socket() fails, then connect() will fail. If connect() fails, then send() will fail as will recv(). It is very bad practice to ignore failures!

    Look at my code again:
    1. If WSAStartup fails, I report the failure and exit the program. That way, I never even try to call socket().
    2. If WSAStartup succeeds, then I call socket(). If socket() fails, then I report the failure and exit the program.
    3. If socket() suceeds, then I call connect(). If connect() fails, then I report the failure and exit the program.
    And so on.

    We have actually had others here starting to work on sockets programming who did not do any error checking or handling. They'd be wracking their brains for days trying to figure out why recv() wouldn't work when the problem was that socket() had failed, but recv() was the first place that they bothered to test for errors. Days of effort wasted for want of a little simple error checking and handling.

    Also, after WSAStartup succeeds in loading and initializing the Winsock DLL, you can use the WSAGetLastError function to get a reason why socket(), connect(), or the other sockets functions fail.


    Originally Posted by miz6565
    I just have one concern. Should I allocate memory when I call the recv function since I don't know how much data HTTP will send me? (you said that on your website).
    Could you please point me to where I said that? I will need to see the context to understand what I was talking about.

    I think that what I was talking about was that you cannot rely on receiving the entire response in just one call to recv, but that you would need to call it more than once to get an entire response. So what you do is that you declare a buffer that should be large enough to be efficient and you call recv telling it to return no more bytes than your buffer can contain -- that was the 2000 that you passed it. If you received the entire message, then you can proceed. But if you have not received the entire message yet, then you need to call recv again to get the rest. Unfortunately, recv blocks, which means that if you have receive the entire message and you call recv again, then it won't return until it receives more data from the server, which won't happen until you send another request which can't happen because you're stuck at recv.

    So the question is: How can you tell when you've received the entire message?

    Let's start with a code fragment from the gethttp utility that illustrates this handling of recv and one way of detecting the end:
    Code:
    	//
    	// Format the HTTP request
    	//
    	char szBuffer[1024];
    
    	sprintf(szBuffer, "GET %s\n", lpFileName);
    	nRet = send(Socket, szBuffer, strlen(szBuffer), 0);
    	if (nRet == SOCKET_ERROR)
    	{
    		PRINTERROR("send()");
    		closesocket(Socket);	
    		return;
    	}
    
    	//
    	// Receive the file contents and print to stdout
    	//
    	while(1)
    	{
    		// Wait to receive, nRet = NumberOfBytesReceived
    		nRet = recv(Socket, szBuffer, sizeof(szBuffer), 0);
    		if (nRet == SOCKET_ERROR)
    		{
    			PRINTERROR("recv()");
    			break;
    		}
    
    		fprintf(stderr,"\nrecv() returned %d bytes", nRet);
    
    		// Did the server close the connection?
    		if (nRet == 0)
    			break;
    		// Write to stdout
            fwrite(szBuffer, nRet, 1, stdout);
    	}
    	closesocket(Socket);	
    }
    recv returns one of three values:
    -1 for error
    >0 for the number of bytes received. This is a very important value to save and use.
    0 for shutdown.

    When you want to close the connection, you do it gracefully by calling the shutdown() function. This will finish sending all the data you had buffered to be sent and then will send a special signal to the remote host. That remote host (AKA "the peer") will receive the data with return values greater than zero and then when it calls recv again it will get a return value of zero that tells it to shutdown.

    You can see where the return value of recv is saved in nRet. If it's -1 (SOCKET_ERROR), then you exit with an error. If it's zero, then the connection has been closed and so you exit. If it's greater than zero, then you fwrite that nRet bytes to the output file and loop back to call recv again.

    This utility appears to be depending on the server always closing the connection after having sent the response. This was the behavior in HTTP/0.9 and HTTP/1.0 (as per Wikipedia, http://en.wikipedia.org/wiki/Http#Pe...nt_connections), but HTTP/1.1 can keep that connection open for more requests, which is more efficient. Instead, the client can take advantage of the Content-length line in the response header. From the header, you know how many bytes of content there is, so you use nRet to keep a count of how many bytes you've recv'd from this response.
  28. #15
  29. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Mar 2013
    Posts
    101
    Rep Power
    0
    The first question I have is whether it did connect to the HTTP server. If it did, then that should have been a good feeling.
    I did get an output saying:
    Code:
    HTTP/1.1 200 OK
    Date: Thu, 20 Jun 2013 18:03:25 GMT
    Expires: -1
    Cache-Control: private, max-age=0
    Content-Type: text/html; charset=ISO-8859-1
    Set-Cookie: PREF=ID=fd76cb4e51428183:FF=0:TM=1371751405:LM=1371751405:S=mLR9YVc0
    rjmmroQb; expires=Sat, 20-Jun-2015 18:03:25 GMT; path=/; domain=.google.com
    Set-Cookie: NID=67=g6fQOcbew-9kVEQmmyKVnuvdOCEwkMy3mp6Venk7Rb0PlZXirKx6qKbUyxfVU
    tPHliBjOEsiEJ2nuKe2L8kGBCW20nppifdG50g8rNhpR3w1ptn5M0QVXxdjWLread5t; expires=Fri
    , 20-Dec-2013 18:03:25 GMT; path=/; domain=.google.com; HttpOnly
    P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bi
    n/answer.py?hl=en&answer=151657 for more info."
    Server: gws
    X-XSS-Protection: 1; mode=block
    X-Frame-Options: SAMEORIGIN
    Transfer-Encoding: chunked
    
    8000
    <!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage">
    <head><meta content="Search the world's information, including webpages, images,
     videos and more. Google has many special features to help you find exactly what
     you're looking for." name="description"><meta content="noodp" name="robots"><me
    ta itemprop="image" content="/images/google_favicon_128.png"><title>Google</titl
    e><script>(function(){
    window.google={kEI:"7UPDUaK7EcnrrQfwooDwAQ",getEI:function(a){for(var b;a&&(!a.g
    etAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI},h
    ttps:function(){return"https:"==window.location.protocol},kEXPI:"25657,4000116,4
    001350,4002464,4002855,4003242,4003710,4004320,4004334,4004788,4004844,4004943,4
    004949,4005031,4005864,4006038,4006039,4006339,4006426,4006442,4006466,4006727,4
    007009,4007055,4007077,4007080,4007117,4007158,4007160,4007173,4007232,4007244,4
    007286,4007296,4007311,4007322,4007328,4007425,4007445,4007472,4007483,4007489,4
    007490,4007533,4007566,4007683,4007762,4007779,4007788,4007798,4007819",kCSI:{e:
    "25657,4000116,4001350,4002464,4002855,4003242,4003710,4004320,4004334,4004788,4
    004844,4004943,4004949,4005031,4005864,4006038,4006039,4006339,4006426,4006442,4
    006466,,0╖
    Anyway, I'm asking. Should I learn the commands of HTTP or should I just look them up when I'm using it and test with another port?
Page 1 of 4 123 ... Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo