create socket by fork

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <errno.h>

//--------------------------------------------------------------------
// Function prototype
//--------------------------------------------------------------------
void signal_handler(int signum);

//--------------------------------------------------------------------
// Main function
//--------------------------------------------------------------------
int main(int argc, char **argv)
{
  int listening_socket;
  unsigned short port;
  int backlog;

  //------------------------------------------------------------------
  // Parse command line arguments
  //------------------------------------------------------------------
  port = (unsigned short) strtol(argv[2], NULL, 10);
  backlog = (int) strtol(argv[3], NULL, 10);

  //------------------------------------------------------------------
  // step 1, create socket
  //------------------------------------------------------------------
  //int socket(int domain, int type, int protocol);
  if ((listening_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  {
    // failed
    fprintf(stderr, "[%d]Create new TCP socket failed: %s\n", getpid(), strerror(errno));
    exit(1);
  }

  fprintf(stderr, "[%d]New TCP socket created, listening_socket = %d\n", getpid(), listening_socket);

  //------------------------------------------------------------------
  // Set SO_REUSEADDR & SO_REUSEPORT options
  //------------------------------------------------------------------
  int optval;

  optval = 1;

  //int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
  if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
  {
    fprintf(stderr, "[%d]Set socket option SO_REUSEADDR failed: %s\n", getpid(), strerror(errno));
  }
  else
  {
    fprintf(stderr, "[%d]Set socket option SO_REUSEADDR successfully.\n", getpid());
  }

#ifdef SO_REUSEPORT
  optval = 1;

  //int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
  if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0)
  {
    fprintf(stderr, "[%d]Set socket option SO_REUSEPORT failed: %s\n", getpid(), strerror(errno));
  }
  else
  {
    fprintf(stderr, "[%d]Set socket option SO_REUSEPORT successfully.\n", getpid());
  }
#endif

  //------------------------------------------------------------------
  // step 2, bind
  //------------------------------------------------------------------
  struct sockaddr_in local_ipv4_address;	// IPv4

  memset(&local_ipv4_address, 0, sizeof(local_ipv4_address));

  local_ipv4_address.sin_family = AF_INET;	// IPv4
  local_ipv4_address.sin_port = htons(port);	// Network byte order

  // int inet_pton(int af, const char *src, void *dst);
  inet_pton(AF_INET, argv[1], &local_ipv4_address.sin_addr);

  // Bind all interfaces
  //local_ipv4_address.sin_addr.s_addr = INADDR_ANY;

  //int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
  if (bind(listening_socket, (struct sockaddr *) &local_ipv4_address, sizeof(local_ipv4_address)) < 0)
  {
    fprintf(stderr, "[%d]Bind to %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno));
    close(listening_socket);
    exit(1);
  }

  fprintf(stderr, "[%d]Bound to %s:%d successfully.\n", getpid(), argv[1], port);

  //------------------------------------------------------------------
  // step 3, listen
  //------------------------------------------------------------------
  //int listen(int sockfd, int backlog);
  if (listen(listening_socket, backlog) < 0)
  {
    fprintf(stderr, "[%d]Listen on %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno));
    close(listening_socket);
    exit(1);
  }

  fprintf(stderr, "[%d]Listen on %s:%d successfully.\n", getpid(), argv[1], port);
  fprintf(stderr, "[%d]Waiting for incomming connections ...\n", getpid());

  //------------------------------------------------------------------
  // Register signal handler
  //------------------------------------------------------------------
  struct sigaction act, oact;

#if 0
  struct sigaction
  {
    void (*sa_handler) (int);
    void (*sa_sigaction) (int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer) (void);
  };
#endif

  memset(&act, 0, sizeof(act));

  act.sa_handler = signal_handler;
  //int sigemptyset(sigset_t *set);
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;

  //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  sigaction(SIGCHLD, &act, &oact);

  //------------------------------------------------------------------
  // Main loop
  //------------------------------------------------------------------
  for (;;)
  {
    //----------------------------------------------------------------
    // accept(), create a new_connected_socket
    //----------------------------------------------------------------
    /*
     * The accept() system call is used  with  connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). 
     *
     * It extracts the first connection request on the queue of pending connections, creates a new connected 
     * socket, and returns a new file descriptor referring to that socket.   
     *
     * The newly created socket is not in the listening state(in ESTABLISHED state)
     * 
     * The original socket sockfd is unaffected by this call(still in LISTEN state)
     */

    int new_connected_socket;
    struct sockaddr_in peer_ipv4_address;
    socklen_t peer_ipv4_address_length;

    // peer_ipv4_address_length is a value-result parameter
    peer_ipv4_address_length = sizeof(peer_ipv4_address);

    //int accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen);
    if ((new_connected_socket = accept(listening_socket, (struct sockaddr *) &peer_ipv4_address, &peer_ipv4_address_length)) < 0)
    {
      // failed
      if (errno == EINTR)
      {
	// Interrupted by signal
	continue;
      }
      else
      {
	// TODO: check other error code
      }

      fprintf(stderr, "[%d]Accept new connections on socket %d failed: %s\n", getpid(), listening_socket, strerror(errno));
      break;
    }
    else
    {
      // success
      char peer_ipv4_address_string[] = "ddd.ddd.ddd.ddd";

      //const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
      inet_ntop(AF_INET, &peer_ipv4_address.sin_addr, peer_ipv4_address_string, sizeof(peer_ipv4_address_string));

      fprintf(stderr, "[%d]Accepted a new connection %d from %s:%d.\n", getpid(), new_connected_socket, peer_ipv4_address_string, ntohs(peer_ipv4_address.sin_port));

      pid_t pid;

      if ((pid = fork()) < 0)
      {
	// failed
	fprintf(stderr, "[%d]Create new process failed: %s\n", getpid(), strerror(errno));
	//FIXME: How to do?
      }
      else if (pid == 0)
      {
	// child process
	close(listening_socket);

	//--------------------------------------------------------------
	// Compose current time information
	//--------------------------------------------------------------
	// time_t time(time_t *t);
	time_t now = time(NULL);

	struct tm *tm;

	//struct tm *localtime(const time_t *timep);
	tm = localtime(&now);

	char buffer[128];

#if 0
	struct tm
	{
	  int tm_sec;		/* seconds */
	  int tm_min;		/* minutes */
	  int tm_hour;		/* hours */
	  int tm_mday;		/* day of the month */
	  int tm_mon;		/* month */
	  int tm_year;		/* year */
	  int tm_wday;		/* day of the week */
	  int tm_yday;		/* day in the year */
	  int tm_isdst;		/* daylight saving time */
	};
#endif

	memset(buffer, 0, sizeof(buffer));

	//int snprintf(char *str, size_t size, const char *format,...);
	snprintf(buffer, sizeof(buffer) - 1, "Current time: %04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

	//--------------------------------------------------------------
	// Send current time to client
	//--------------------------------------------------------------
	ssize_t n;

	//ssize_t write(int listening_socket, const void *buf, size_t count);
	if ((n = write(new_connected_socket, buffer, strlen(buffer))) < 0)
	{
	  fprintf(stderr, "[%d]Send data to client fialed: %s\n", getpid(), strerror(errno));
	}
	else
	{
	  fprintf(stderr, "[%d]Sent %d bytes (\"%s\" to client successfully.\n", getpid(), n, buffer);
	}

	//--------------------------------------------------------------
	// close new_connected_socket
	//--------------------------------------------------------------
	close(new_connected_socket);

	exit(0);		// child process termination, very important
      }
      else
      {
	// parent
	close(new_connected_socket);
      }
    }
  }

  //------------------------------------------------------------------
  // final, close listening_socket
  //------------------------------------------------------------------
  close(listening_socket);

  return 0;
}

void signal_handler(int signum)
{
  fprintf(stderr, "[%d]Caught signal %d.\n", getpid(), signum);

  pid_t pid;
  int status;

  //pid_t wait(int *status);
  if ((pid = wait(&status)) < 0)
  {
    // failed
    fprintf(stderr, "wait() failed: %s\n", strerror(errno));
  }
  else
  {
    fprintf(stderr, "[%d]Child process %d terminated, status = 0x%08x\n", getpid(), pid, status);

    // check status
  }
}

// vim:tabstop=8


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值