Exercise: Socket Programming with Event loop
Server Flow
Creation of socket-based connections requires several operations.
First, a socket is created with socket.
Second, bound to an address with bind. Next, a willingness to accept incoming connections and a queue limit for incoming connections are specified with listen.
Finally, the connections are accepted with accept.
Accept a connection on a socket
accept() extracts the first connection request on the queue of pending connections, creates a new socket with the same properties of socket, and allocates a new file descriptor for the socket.
If no pend-ing connections are present on the queue, and the socket is not marked as non-blocking, accept() blocks the caller until a connection is present.
Code
/*
* tcpserver.c - A simple TCP echo server
* usage: tcpserver <port>
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define BUFSIZE 1024
/*
* error - wrapper for perror
*/
void error(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv) {
int parentfd; /* parent socket */
int childfd; /* child socket */
int portno; /* port to listen on */
int clientlen; /* byte size of client’s address */
struct sockaddr_in serveraddr; /* server's addr */
struct sockaddr_in clientaddr; /* client addr */
struct hostent *hostp; /* client host info */
char buf[BUFSIZE]; /* message buffer */
char *hostaddrp; /* dotted decimal host addr string */
int optval; /* flag value for setsockopt */
int n; /* message byte size */
/*
* check command line arguments
*/
if (argc != 2) {
fprintf(stderr, “usage: %s <port>\n”, argv[0]);
exit(1);
}
portno = atoi(argv[1]);
/*
* socket: create the parent socket
*/
parentfd = socket(AF_INET, SOCK_STREAM, 0);
if (parentfd < 0)
error("ERROR opening socket");
/* setsockopt: Handy debugging trick that lets
* us rerun the server immediately after we kill it;
* otherwise we have to wait about 20 secs.
* Eliminates "ERROR on binding: Address already in use" error.
*/
optval = 1;
setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int));
/*
* build the server’s Internet address
*/
bzero((char *) &serveraddr, sizeof(serveraddr));
/* this is an Internet address */
serveraddr.sin_family = AF_INET;
/* let the system figure out our IP address */
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
/* this is the port we will listen on */
serveraddr.sin_port = htons((unsigned short)portno);
/*
* bind: associate the parent socket with a port
*/
if (bind(parentfd, (struct sockaddr *) &serveraddr,
sizeof(serveraddr)) < 0)
error(“ERROR on binding”);
/*
* listen: make this socket ready to accept connection requests
*/
if (listen(parentfd, 5) < 0) /* allow 5 requests to queue up */
error(“ERROR on listen”);
/*
* main loop: wait for a connection request, echo input line,
* then close connection.
*/
clientlen = sizeof(clientaddr);
while (1) {
/*
* accept: wait for a connection request
*/Client Flow
First, a socket is created with socket.
Second, build the server’s Internet address. Next, create a connection with the server with connect. Finally, send the message line to the server, and print server’s reply using (write, and read).
Code
Use select for event loop
select for event loopUse kqueue for event loop
kqueue for event loopIn Mac, kqueue is similar to epoll.
EV_SET adds parentfd to event set, and monitor when fds is ready for reading. If the result in evList contains the parentfd, we know there is a queued connection, so we start to handle.
A multithreading TCP client
Makefile Example
References
Last updated
Was this helpful?