linux c socket之多进程任务

来源:互联网 发布:检测usb端口软件 编辑:程序博客网 时间:2024/06/11 23:25
/*  * File:   TCPEchoServer-Fork.c * Author: 云守护 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/wait.h>#include "Utility.h"int main(int argc, char** argv) {    if (argc != 2)        DieWithUserMessage("param", "<server port/Service>");    char *service = argv[1];    int server_sock = SetupTCPServerSocket(service);    if (server_sock < 0)        DieWithUserMessage("SetupTCPServerSocket() failed!", "unable to establish");    unsigned int childProcCount = 0;    for (;;) {        int client_sock = AcceptTCPConnection(server_sock);        pid_t pid = fork(); //新进程        if (pid < 0)            DieWithSystemMessage("fork() failed!");        else if (pid == 0) {            //子进程            close(server_sock);            HandleTCPClient(client_sock);            exit(0);        }        //父进程        printf("with child process:%d\n", pid);        close(client_sock);        childProcCount++; //子进程加一        while (childProcCount)//清除所有僵尸进程        {            pid = waitpid((pid_t) - 1, NULL, WNOHANG); //非阻塞等待            if (pid < 0)                DieWithSystemMessage("waitpid() failed!");            else if (pid == 0)                break;            else                childProcCount--;        }    }    return (EXIT_SUCCESS);}
/*  * File:   Utility.h * Author: 云守护 542335495@qq.com */#ifndef UTILITY_H#defineUTILITY_H#ifdef__cplusplusextern "C" {#endif#include <stdbool.h>#include <stdio.h>#include <sys/socket.h>// Handle error with user msgvoid DieWithUserMessage(const char *msg, const char *detail);// Handle error with sys msgvoid DieWithSystemMessage(const char *msg);// Print socket addressvoid PrintSocketAddress(const struct sockaddr *address, FILE *stream);// Test socket address equalitybool SockAddrsEqual(const struct sockaddr *addr1, const struct sockaddr *addr2);// Create, bind, and listen a new TCP server socketint SetupTCPServerSocket(const char *service);// Accept a new TCP connection on a server socketint AcceptTCPConnection(int servSock);// Handle new TCP clientvoid HandleTCPClient(int clntSocket);// Create and connect a new TCP client socketint SetupTCPClientSocket(const char *server, const char *service);enum sizeConstants {  MAXSTRINGLENGTH = 128,  BUFSIZE = 512,};#ifdef__cplusplus}#endif#endif/* UTILITY_H */
/*  * File:   Utility.c * Author: 云守护 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include "Utility.h"static const int MAXPENDING = 5; // Maximum outstanding connection requestsvoid DieWithUserMessage(const char *msg, const char *detail) {  fputs(msg, stderr);  fputs(": ", stderr);  fputs(detail, stderr);  fputc('\n', stderr);  exit(1);}void DieWithSystemMessage(const char *msg) {  perror(msg);  exit(1);}void PrintSocketAddress(const struct sockaddr *address, FILE *stream) {  // Test for address and stream  if (address == NULL || stream == NULL)    return;  void *numericAddress; // Pointer to binary address  // Buffer to contain result (IPv6 sufficient to hold IPv4)  char addrBuffer[INET6_ADDRSTRLEN];  in_port_t port; // Port to print  // Set pointer to address based on address family  switch (address->sa_family) {  case AF_INET:    numericAddress = &((struct sockaddr_in *) address)->sin_addr;    port = ntohs(((struct sockaddr_in *) address)->sin_port);    break;  case AF_INET6:    numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr;    port = ntohs(((struct sockaddr_in6 *) address)->sin6_port);    break;  default:    fputs("[unknown type]", stream);    // Unhandled type    return;  }  // Convert binary to printable address  if (inet_ntop(address->sa_family, numericAddress, addrBuffer,      sizeof(addrBuffer)) == NULL)    fputs("[invalid address]", stream); // Unable to convert  else {    fprintf(stream, "%s", addrBuffer);    if (port != 0)                // Zero not valid in any socket addr      fprintf(stream, "-%u", port);  }}bool SockAddrsEqual(const struct sockaddr *addr1, const struct sockaddr *addr2) {  if (addr1 == NULL || addr2 == NULL)    return addr1 == addr2;  else if (addr1->sa_family != addr2->sa_family)    return false;  else if (addr1->sa_family == AF_INET) {    struct sockaddr_in *ipv4Addr1 = (struct sockaddr_in *) addr1;    struct sockaddr_in *ipv4Addr2 = (struct sockaddr_in *) addr2;    return ipv4Addr1->sin_addr.s_addr == ipv4Addr2->sin_addr.s_addr        && ipv4Addr1->sin_port == ipv4Addr2->sin_port;  } else if (addr1->sa_family == AF_INET6) {    struct sockaddr_in6 *ipv6Addr1 = (struct sockaddr_in6 *) addr1;    struct sockaddr_in6 *ipv6Addr2 = (struct sockaddr_in6 *) addr2;    return memcmp(&ipv6Addr1->sin6_addr, &ipv6Addr2->sin6_addr,        sizeof(struct in6_addr)) == 0 && ipv6Addr1->sin6_port        == ipv6Addr2->sin6_port;  } else    return false;}int SetupTCPClientSocket(const char *host, const char *service) {  // Tell the system what kind(s) of address info we want  struct addrinfo addrCriteria;                   // Criteria for address match  memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure  addrCriteria.ai_family = AF_UNSPEC;             // v4 or v6 is OK  addrCriteria.ai_socktype = SOCK_STREAM;         // Only streaming sockets  addrCriteria.ai_protocol = IPPROTO_TCP;         // Only TCP protocol  // Get address(es)  struct addrinfo *servAddr; // Holder for returned list of server addrs  int rtnVal = getaddrinfo(host, service, &addrCriteria, &servAddr);  if (rtnVal != 0)    DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));  int sock = -1;  struct addrinfo *addr = servAddr;  while ( addr != NULL) {    // Create a reliable, stream socket using TCP    sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);    if (sock < 0)      continue;  // Socket creation failed; try next address    // Establish the connection to the echo server    if (connect(sock, addr->ai_addr, addr->ai_addrlen) == 0)      break;     // Socket connection succeeded; break and return socket    close(sock); // Socket connection failed; try next address    sock = -1;    addr = addr->ai_next;  }  freeaddrinfo(servAddr); // Free addrinfo allocated in getaddrinfo()  return sock;}int SetupTCPServerSocket(const char *service) {  // Construct the server address structure  struct addrinfo addrCriteria;                   // Criteria for address match  memset(&addrCriteria, 0, sizeof(addrCriteria)); // Zero out structure  addrCriteria.ai_family = AF_UNSPEC;             // Any address family  addrCriteria.ai_flags = AI_PASSIVE;             // Accept on any address/port  addrCriteria.ai_socktype = SOCK_STREAM;         // Only stream sockets  addrCriteria.ai_protocol = IPPROTO_TCP;         // Only TCP protocol  struct addrinfo *servAddr; // List of server addresses  int rtnVal = getaddrinfo(NULL, service, &addrCriteria, &servAddr);  if (rtnVal != 0)    DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal));  int servSock = -1;  struct addrinfo *addr = servAddr;  while ( addr != NULL) {    // Create a TCP socket    servSock = socket(addr->ai_family, addr->ai_socktype,        addr->ai_protocol);    if (servSock < 0)      continue;       // Socket creation failed; try next address    // Bind to the local address and set socket to listen    if ((bind(servSock, addr->ai_addr, addr->ai_addrlen) == 0) &&        (listen(servSock, MAXPENDING) == 0)) {      // Print local address of socket      struct sockaddr_storage localAddr;      socklen_t addrSize = sizeof(localAddr);      if (getsockname(servSock, (struct sockaddr *) &localAddr, &addrSize) < 0)        DieWithSystemMessage("getsockname() failed");      fputs("Binding to ", stdout);      PrintSocketAddress((struct sockaddr *) &localAddr, stdout);      fputc('\n', stdout);      break;       // Bind and listen successful    }    close(servSock);  // Close and try again    servSock = -1;    addr = addr->ai_next;  }  // Free address list allocated by getaddrinfo()  freeaddrinfo(servAddr);  return servSock;}int AcceptTCPConnection(int servSock) {  struct sockaddr_storage clntAddr; // Client address  // Set length of client address structure (in-out parameter)  socklen_t clntAddrLen = sizeof(clntAddr);  // Wait for a client to connect  int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen);  if (clntSock < 0)    DieWithSystemMessage("accept() failed");  // clntSock is connected to a client!  fputs("Handling client ", stdout);  PrintSocketAddress((struct sockaddr *) &clntAddr, stdout);  fputc('\n', stdout);  return clntSock;}void HandleTCPClient(int clntSocket) {  char buffer[BUFSIZE]; // Buffer for echo string  memset(buffer,0,sizeof(buffer));  // Receive message from client  ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);  if (numBytesRcvd < 0)    DieWithSystemMessage("recv() failed");  puts(buffer);  putc('\n',stdout);  // Send received string and receive again until end of stream  while (numBytesRcvd > 0) { // 0 indicates end of stream    // Echo message back to client    ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);    if (numBytesSent < 0)      DieWithSystemMessage("send() failed");    else if (numBytesSent != numBytesRcvd)      DieWithUserMessage("send()", "sent unexpected number of bytes");    // See if there is more data to receive    numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);    if (numBytesRcvd < 0)      DieWithSystemMessage("recv() failed");  }  close(clntSocket); // Close client socket}



原创粉丝点击