Linux sockets
Jump to navigation
Jump to search
Tutorials
- A thoough step-by-step example of client and socket code.
- Simple example of client and server code using Linux sockets.
References
- A very detailed answer about the differences between
SO_REUSEADDR
andSO_REUSEPORT
.
- A course on internet technologies, including Domain Naming (DNS...), the IP protocol, the TCP protocol, ...
- Manpages:
C socket
- read(2) - Read from a file descriptor
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- Mostly equivalent to
recv
,recvfrom
andrecvmsg
.
- recv(2), recvfrom(2), recmmsg(2) - Receive a message from a socket
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
- write(2) - Write to a file descriptor
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- The main difference with
send
is that whenwrote
returnsEPIPE
, the writing process will also receive a SIGPIPE signal, terminating it unless it catches it or ignore it.
- send(2), sendto(2), sendmsg(2) - Send a message on a socket
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
- The main difference with
write
is the presence offlags
, which among other can configured to prevent the generation of SIGPIPE signal.
Troubleshooting
Use errno / perror / strerror to get error
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
printf("bind failed: %s (errno %d)", strerror(errno), errno);
return 1;
}
Or there is also the perror
function:
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
perror("bind failed");
return 1;
}
Use netstat
to get socket status
./server
# bind done
# Waiting for incoming connections...
# Connection accepted
# Handler assigned
# ^C
./server
# bind failed: Address already in use (errno 98)
netstat -a | grep 8888
# tcp 0 0 zavcxl0005:58888 165.225.76.32:http ESTABLISHED
# tcp 0 0 zavcxl0005:48888 10.75.126.1:https ESTABLISHED
# tcp 0 0 localhost.localdom:8888 localhost.localdo:50310 TIME_WAIT
# ... So port is still in use
bind failed: Address already in use (errno 98)
Call to bind
fails with error
bind failed: Address already in use (errno 98)
On a server, this is probably due to an old instance of the server that tries to bind to the same port and address [1].
As a fix, try to bind with option SO_REUSEADDR
and/or SO_REUSEPORT
. From SO:
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
For more information, see socket(7) and ip(7) manpages.
Program crashes on write
with exit code -13
Exit code -13 means the program died because of SIGPIPE signal, meaning it tried to write to a closed socket.
Solutions:
- Ignore SIGPIPE in the program [2]:
signal (SIGPIPE, SIG_IGN);
- Use
send
instead ofwrite
. Send returns -1 and seterrno
toEPIPE
rather than generating a fatal SIGPIPE likewrite
does [3]:
n = send(newsockfd, data.c_str(), data.length()+1, MSG_NOSIGNAL);