-1

Because of specifications requirement, I'm not allowed to use recv() or similar functions to read from socket's fd. I was wondering how I would remake that function using read()?

I've attempted creating it with the following code

int recvFromFd(int connectionFd, char *buf, int size)
{
    char c;
    int i = 0;
    for (read(connectionFd, &c, 1); i < size; i++)
    {
        buf[i] = c;
        if (c == '\n' || read(connectionFd, &c, 1) == EOF)
            break;
    }
    return i;
}

This code works to an extent, but often when when the sender send one message after another, the function read both of those message at the same time to the same buffer (appends).

user10416282
  • 33
  • 1
  • 7
  • 2
    What kind of connection is used there? datagram? flow? Looks like your are trying to achieve message passing in a stream, and that need a precise format of what a message is. – Jean-Baptiste Yunès Apr 16 '19 at 06:52
  • 1
    As long as the flags argument to `recv()` is 0, and you're not on Windows or dealing with 0-length datagrams, it and `read()` are interchangable. – Shawn Apr 16 '19 at 06:53
  • 1
    Looks like your real question is "how do I read a line of text from a socket"? – Shawn Apr 16 '19 at 06:57
  • @Jean-BaptisteYunès sockets tcp connections. – user10416282 Apr 16 '19 at 07:00
  • @Shawn what about Ubuntu terminal on windows? – user10416282 Apr 16 '19 at 07:00
  • @user10416282 ubuntu terminal on windows is nothing more than a simulation. Its ability is confined up to somewhere. I suggest you shouldn't rely on that. – Soner from The Ottoman Empire Apr 16 '19 at 07:06
  • @user10416282 read never returns EOF instead it returns 0 to indicate EOF – Soner from The Ottoman Empire Apr 16 '19 at 07:10
  • Your loop is not correct. It is never correct to call `read()` or `recv()` without storing the result into a variable, as you have to test it for both 0 and -1, and if neither you still have to use the result as the read length. You can't accomplish all that without a variable. And reading one byte at a time is terribly inefficient. – user207421 Apr 16 '19 at 07:18

2 Answers2

0

You can use read(2) in place of recv(2) on Unix (but I'm not sure if it works on Windows, where is no read() function). But read() function has some limitations:

  1. You can't get peer's address (in case of UDP protocol);

  2. You can't receive zero sized datagrams (UDP);

  3. You can't pass file descriptors (via unix domain socket);

  4. You can't work with special socket types (AF_NETLINK domain, SOCK_SEQPACKET socket type), which is used to obtain network configuration from the kernel.

Linux manpage says:

The only difference between recv() and read(2) is the presence of flags. With a zero flags argument, recv() is generally equivalent to read(2).

As I think, for TCP protocol where is almost no difference in use of read(2) or recv(2).

user207421
  • 305,947
  • 44
  • 307
  • 483
Kirill Frolov
  • 401
  • 4
  • 10
  • If that's what the Linux manpage says, it contradicts your second point. – user207421 Apr 16 '19 at 07:14
  • can you explain to me zero sized datagrams ? – user10416282 Apr 16 '19 at 07:31
  • On one side you can call send(socket, "", 0, 0). This does nothing for TCP socket, but in case in UDP socket it sends to network distinct UDP packet with no payload. Such packet can be detected on receiving side by calling recvmsg(2) function. Functions like read(2) and recv(2) can't distinguish between zero-sized datagram and "end of file" condition (when function returns zero), or absence of the data (in case of non-blocking socket). In some protocols zero-sized datagrams used as "end of record" marker, as way to send "out of band" data. – Kirill Frolov Apr 16 '19 at 07:39
  • That's all very well but you are claiming without evidence that `read()` cannot deliver a zero length datagram, which flatly contradicts the Linux page you are quoting from. – user207421 Apr 16 '19 at 10:39
  • In case of receiving zero length datagram read(2) returns zero. So you can't distinguish this condition with end of file. I know this, because "netcat" terminates when receiving zero-sized datagram. May be this is linux specific thing and other Unices have different behaviour. I don't know. – Kirill Frolov Apr 16 '19 at 21:07
0

So I ended up doing the following and it works.

int recvFromFd(int connectionFd, char *buf, int size)
{
    char c;
    int i = 0;
    for (read(connectionFd, &c, 1); i < size && c != '\n'; i++)
    {
        buf[i] = c;
        read(connectionFd, &c, 1);
    }
    buf[i] = '\0';
    if (debugMode)
        printf("\n>Incoming from socket: %s\n", buf);
    return i; // how many was read
}
user10416282
  • 33
  • 1
  • 7