How Do Sockets Work in C?

前端 未结 4 921
渐次进展
渐次进展 2021-02-04 02:02

I am a bit confused about socket programming in C.

You create a socket, bind it to an interface and an IP address and get it to listen. I found a couple of web resources

相关标签:
4条回答
  • 2021-02-04 02:17

    Sockets operate at a higher level than raw packets - it's like a file you can read/write from. Also, when you try to read from a socket, the operating system will block (put on hold) your process until it has data to fulfill the request.

    0 讨论(0)
  • 2021-02-04 02:21

    So, the answer to your question depends a fair bit on whether you are using UDP or TCP as your transport.

    For UDP, life gets a lot simpler, in that you can call recv/recvfrom/recvmsg with the packet size you need (you'd likely send fixed-length packets from the source anyway), and make the assumption that if data is available, it's there in multiples of packet-length sizes. (I.E. You call recv* with the size of your sending side packet, and you're set.)

    For TCP, life gets a bit more interesting - for the purpose of this explanation, I will assume that you already know how to use socket(), bind(), listen() and accept() - the latter being how you get the file descriptor (FD) of your newly made connection.

    There are two ways of doing the I/O for a socket - blocking, in which you call read(fd, buf, N) and the read sits there and waits until you've read N bytes into buf - or non-blocking, in which you have to check (using select() or poll()) whether the FD is readable, and THEN do your read().

    When dealing with TCP-based connections, the OS doesn't pay attention to the packet sizes, since it's considered a continual stream of data, not seperate packet-sized chunks.

    If your application uses "packets" (packed or unpacked data structures that you're passing around), you ought to be able to call read() with the proper size argument, and read an entire data structure off the socket at a time. The only caveat you have to deal with, is to remember to properly byte-order any data that you're sending, in case the source and destination system are of different byte endian-ness. This applies to both UDP and TCP.

    As far as *NIX socket programming is concerned, I highly recommend W. Richard Stevens' "Unix Network Programming, Vol. 1" (UNPv1) and "Advanced Programming in an Unix Environment" (APUE). The first is a tome regarding network-based programming, regardless of the transport, and the latter is a good all-around programming book as it applies to *NIX based programming. Also, look for "TCP/IP Illustrated", Volumes 1 and 2.

    0 讨论(0)
  • 2021-02-04 02:22

    When you do a read on the socket, you tell it how many maximum bytes to read, but if it doesn't have that many, it gives you however many it's got. It's up to you to design the protocol so you know whether you've got a partial packet or not. For instance, in the past when sending variable length binary data, I would put an int at the beginning that said how many bytes to expect. I'd do a read requesting a number of bytes greater than the largest possible packet in my protocol, and then I'd compare the first int against however many bytes I'd received, and either process it or try more reads until I'd gotten the full packet, depending.

    0 讨论(0)
  • 2021-02-04 02:34

    Short answer is that you have to do all the heavy lifting yourself. You can be notified that there is data available to be read, but you won't know how many bytes are available. In most IP protocols that use variable length packets, there will be a header with a known fixed length prepended to the packet. This header will contain the length of the packet. You read the header, get the length of the packet, then read the packet. You repeat this pattern (read header, then read packet) until communication is complete.

    When reading data from a socket, you request a certain number of bytes. The read call may block until the requested number of bytes are read, but it can return fewer bytes than what was requested. When this happens, you simply retry the read, requesting the remaining bytes.

    Here's a typical C function for reading a set number of bytes from a socket:

    /* buffer points to memory block that is bigger than the number of bytes to be read */
    /* socket is open socket that is connected to a sender */
    /* bytesToRead is the number of bytes expected from the sender */
    /* bytesRead is a pointer to a integer variable that will hold the number of bytes */
    /*           actually received from the sender. */
    /* The function returns either the number of bytes read, */
    /*                             0 if the socket was closed by the sender, and */
    /*                            -1 if an error occurred while reading from the socket */
    int readBytes(int socket, char *buffer, int bytesToRead, int *bytesRead)
    {
        *bytesRead = 0;
        while(*bytesRead < bytesToRead)
        {
            int ret = read(socket, buffer + *bytesRead, bytesToRead - *bytesRead);
            if(ret <= 0)
            {
               /* either connection was closed or an error occurred */
               return ret;
            }
            else
            {
               *bytesRead += ret;
            }
        }
        return *bytesRead;
    }
    
    0 讨论(0)
提交回复
热议问题