Sockets Programming Quick Reference
Overview
See the https://beej.us/guide/bgnet/ or the man pages for more detailed descriptions of the functions
Client Programming: socket()
, getaddrinfo/inet_aton/inet_addr/inet_pton
, connect()
, recv()/send()
Server Programming: socket()
, getaddrinfo/inet_aton/inet_addr/inet_pton
, bind()
, listen()
, accept()
, recv()/send()
socket()
int socket(int domain, int type, int protocol);
- The domain specifies what type of socket we want---for this lecture, it will be one of
PF_INET
orPF_INET6
- The type for this lecture will always be
SOCK_STREAM
(meaning TCP, it could also beSOCK_DGRAM
forUDP
) - The protocol is the protocol number (e.g., one of
IPPROTO_TCP
orIPPROTO_UDP
, but we can use0
sinceSOCK_STREAM
means TCP, and it will figure it out) - Returns a "file descriptor" on success and
<0
on error (setting errno as appropriate)
struct sockaddr
struct sockaddr
is the generic type for a socket address, but we'll usestruct sockaddr_in
orstruct sockaddr_in6
and cast to astruct sockaddr
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
struct in_addr {
uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
inet_pton()
, inet_addr()
, and inet_aton()
aton
andaddr
only work for IPv4 addressesint inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
cp
is a string of a dotted quad IP addressint inet_pton(int af, const char *src, void *dst);
getaddrinfo()
int getaddrinfo(const char *node, // e.g. "www.example.com" or IP
const char *service, // e.g. "http" or port number
const struct addrinfo *hints,
struct addrinfo **res);
- Gives us a linked list of
struct addrinfo
s
struct addrinfo {
int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // use 0 for "any"
size_t ai_addrlen; // size of ai_addr in bytes
struct sockaddr *ai_addr; // struct sockaddr_in or _in6
char *ai_canonname; // full canonical hostname
struct addrinfo *ai_next; // linked list, next node
};
bind()
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
- Binds our socket to the address and port specified by
my_addr
- We will often use
INADDR_ANY
f to indicate that we want to accept any IPv4 connection (slightly different for IPv6, see “Jumping from IPv4 to IPv6” on Beej’s guide)
Also, copied from Beej's guide, if you have an error that the address is already in use, you can fix that as follows
int yes = 1;
// lose the pesky "Address already in use" error message
if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) {
perror("setsockopt");
exit(1);
}
listen()
int listen(int sockfd, int backlog);
- Starts our socket "listening" (what a server would do)
backlog
is how many outstanding requests can be queued until weaccept
them
accept()
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- Returns a file descriptor for a remote connection
- We'll use a
struct sockaddr_storage
(guaranteed large enough to store any address) for the address
struct sockaddr_storage {
sa_family_t ss_family; // address family
// all this is padding, implementation specific, ignore it:
char __ss_pad1[_SS_PAD1SIZE];
int64_t __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
connect()
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
- Useful for the client, connects our local socket to the remote address
send()
int send(int sockfd, const void *msg, int len, int flags);
- Returns how many bytes were actually sent (may be less than we requested, which we'll have to handle)
flags
can be 0 by default- Note that while we could use
write
, we tend to usesend
instead since it lets us to more specific socket things (see theman
page forflags
)
recv()
int recv(int sockfd, void *buf, int len, int flags);
- Returns how many bytes were received (no more than
len
) - Returns
<0
on error,0
when remote side has closed
close()
close(sockfd);
- Prevents any further reads or writes to the socket, the remote peer will receive an error on trying to read or write
- Also, marks the fd as usable again (no longer counts toward our per-process limit)
shutdown()
int shutdown(int sockfd, int how);
- Note that you will still have to
close
eventually
how | Effect |
---|---|
0 | Further receives are disallowed |
1 | Further sends are disallowed |
2 | Further sends and receives are disallowed (like close()) |