My Training Period: xx hours
Note: Program examples if any, compiled using gcc on Linux Fedora Core 3 machine with several update, as normal user. The Fedora machine used for the testing having the "No Stack Execute" disabled and the SELinux set to default configuration.
NAMElisten() - listen for connections on a socketSYNOPSIS#include <sys/socket.h>int listen(int sockfd, int backlog);
NAMEaccept() - accept a connection on a socketSYNOPSIS#include <sys/types.h>#include <sys/socket.h>int accept(int sockfd, struct sockaddr *addr, int *addrlen);
[bodo@bakawali testsocket]$ cat test3.c
/* the port users will be connecting to */
#define MYPORT 3440
/* how many pending connections queue will hold */
#define BACKLOG 10
/* listen on sock_fd, new connection on new_fd */
int sockfd, new_fd;
/* my address information, address where I run this program */
struct sockaddr_in my_addr;
/* remote address information */
struct sockaddr_in their_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
perror("socket() error lol!");
printf("socket() is OK...\n");
/* host byte order */
my_addr.sin_family = AF_INET;
/* short, network byte order */
my_addr.sin_port = htons(MYPORT);
/* auto-fill with my IP */
my_addr.sin_addr.s_addr = INADDR_ANY;
/* zero the rest of the struct */
memset(&(my_addr.sin_zero), 0, 8);
if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
perror("bind() error lol!");
printf("bind() is OK...\n");
if(listen(sockfd, BACKLOG) == -1)
perror("listen() error lol!");
printf("listen() is OK...\n");
/* ...other codes to read the received data... */
sin_size = sizeof(struct sockaddr_in);
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if(new_fd == -1)
perror("accept() error lol!");
printf("accept() is OK...\n");
msg is a pointer to the data you want to send.
len is the length of that data in bytes.
Just set flags to 0. (See the send() man page for more information concerning flags).
Some sample code might be:
char *msg = "I was here!";
int len, bytes_sent;
len = strlen(msg);
bytes_sent = send(sockfd, msg, len, 0);
send() returns the number of bytes actually sent out and this might be less than the number you told it to send.
Sometimes you tell it to send a whole gob of data and it just can’t handle it. It’ll fire off as much of the data as it can, and trust you to send the rest later.
Remember, if the value returned by send() doesn’t match the value in len, it’s up to you to send the rest of the string.
If the packet is small (less than 1K or so) it will probably manage to send the whole thing all in one go.
Again, -1 is returned on error, and errno is set to the error number.
The recv() call is similar in many respects:
int recv(int sockfd, void *buf, int len, unsigned int flags);
sockfd is the socket descriptor to read from, buf is the buffer to read the information into and len is the maximum length of the buffer.
flags can again be set to 0. See the recv() man page for flag information.
recv() returns the number of bytes actually read into the buffer, or -1 on error (with errno set, accordingly).
If recv() return 0, this can mean only one thing that is the remote side has closed the connection on you. A return value of 0 is recv()’s way of letting you know this has occurred.
At this stage you can now pass data back and forth on stream sockets.
These two functions send() and recv() are for communicating over stream sockets or connected datagram sockets.
If you want to use regular unconnected datagram sockets (UDP), you need to use the sendto() and recvfrom().
Or you can use more general, the normal file system functions, write() and read().
NAMEwrite() - write to a file descriptorSYNOPSIS#include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);
Writes to files, devices, sockets etc.
Normally data is copied to a system buffer and write occurs asynchronously.
If buffers are full, write can block.
NAMEread() - read from a file descriptorSYNOPSIS#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
Reads from files, devices, sockets etc.
If a socket has data available up to count bytes are read.
If no data is available, the read blocks.
If less than count bytes are available, read returns what it can without blocking.
For UDP, data is read in whole or partial datagrams. If you read part of a datagram, the rest is discarded.
close() and shutdown()
NAMEclose() - close a file descriptorSYNOPSIS#include <unistd.h>int close(int sockfd);
You can just use the regular UNIX file descriptor close() function:
This will prevent any more reads and writes to the socket. Anyone attempting to read or write the socket on the remote end will receive an error.
UNIX keeps a count of the number of uses for an open file or device.
Close decrements the use count. If the use count reaches 0, it is closed.
Just in case you want a little more control over how the socket closes, you can use the shutdown() function.
It allows you to cut off communication in a certain direction, or both ways just like close() does.
int shutdown(int sockfd, int how);
sockfd is the socket file descriptor you want to shutdown, and how is one of the following:
0 – Further receives are disallowed.
1 – Further sends are disallowed.
2 – Further sends and receives are disallowed (like close()).
shutdown() returns 0 on success, and -1 on error (with errno set accordingly).
If you deign to use shutdown() on unconnected datagram sockets, it will simply make the socket unavailable for further send() and recv() calls (remember that you can use these if you connect() your datagram socket).
It’s important to note that shutdown() doesn’t actually close the file descriptor, it just change its usability.
To free a socket descriptor, you need to use close().
Continue on next Module…More in-depth discussion about TCP/IP suite is given in Advanced TCP/IP Programming.
Further reading and digging: