⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vcserver.c

📁 Linux网络编程配套源代码 不过看的时候最好和书籍一起配套看
💻 C
字号:
/*  vcserver.c  server  */



#include <stdio.h>

#include <errno.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>    /* sockaddr_in 结构体 */



/* 下面的这个include可以使程序查询主机名字列表,

找出所有与其IP绑定的hostname */

#include <netdb.h>          /* 预定义/etc/hosts列表 */

main (int argc, char *argv[])

{

   int rc,            /* 系统调用return code */

       new_sd, sock,  /* server/listen 套接字标识符 */

       adrlen,        /* sockaddr 长度 */

       cnt;           /* number of bytes I/O */

   struct sockaddr_in myname;  /* Internet套接字名称 */

   struct sockaddr_in *nptr;   /* ptr 获取端口号 */

   struct sockaddr    addr;    /* 通用套接字名称 */

   char buf[80];   /* I/O 缓冲区定义 */

   /* 在 /etc/hosts 文件中查找  */

   struct hostent *hp, *gethostbyaddr();

   /* 标识服务器进程,打印其PID */



   printf("\nThis is the network server with pid %d\n",

        getpid() );



   /* 建立一个倾听套接字 */



   if (( sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {

      printf("network server socket failure %d\n", errno);

      perror("network server");

      exit(1);

}

   /* 初始化套接字地址结构中的各个参数              */

   myname.sin_family = AF_INET;  /* Internet地址 */

   myname.sin_port = 0;  /* 系统会绑定端口号  */

   myname.sin_addr.s_addr = INADDR_ANY;  

   /* 将IP地址结构与套接字绑定,调用bind()函数 */



   if (bind(sock, &myname, sizeof(myname) ) < 0 ) {

      close(sock);  /* defensive programming  */

      printf("network server bind failure %d\n", errno);

      perror("network server");

      exit(2);

   }



   /*	获取套接字端口号。调用getsockname()可以得到与套接字相关联

的端口号,并作为套接字地址结构中的一部分返回。记录

这个端口号以供客户端程序使用。

	*/

   adrlen = sizeof(addr); /* 地址长度为整形值 */

   if ( ( rc = getsockname( sock, &addr, &adrlen ) ) < 0 )

	{

      printf("setwork server getsockname failure %d\n",

				errno);

      perror("network server");

      close (sock);

      exit(3);

   }



   /*	调试说明:

通用套接字地址addr被用来存放getsockname()返回的套接字的值。

打印这个信息。在一般的地址声明中,除了地址族其余的都被定

义为字符串类型。Getsocknae()调用之后,这个通用套接字地址

结构addr就会被用来存放关于客户端进程的信息。*/

   printf("\nAfter getsockname():");

   printf(" server listen socket data\n");

   printf("\taddr.sa_family field value is: %d\n",

        addr.sa_family);

   printf("\taddr.sa_data string is %d bytes long;\n",

        sizeof ( addr.sa_data ) );

   printf("\taddr.sa_data string is:");

   for ( cnt = 0; cnt < sizeof (addr.sa_data); cnt++)

        printf(" %x", addr.sa_data[cnt]);

   printf("\n");



   /*	现在需要记录下来套接字的端口号。在这里端口号将作为启动客户端程

序的一个命令行参数使用。  */

   /*	注意指针nptr,它是指向通用套接字地址结构的一个指针		*/



   nptr = (struct sockaddr_in *) &addr;  /* port # */

   printf("\n\tnetwork server: server has port number: %d\n",

      ntohs ( nptr -> sin_port ) );



   /*  调用listen()函数 */

   if ( listen ( sock, 5 ) < 0 ) {

      printf("network server bind failure %d\n", errno);

      perror("network server");

      close (sock);

      exit(4);

   }



   /* 调试输出:

下面输出结构体myname中所包含的套接字信息         */

   printf("Server has set up client socket with values:\n");

   printf("\tInternet address is %lx\n", myname.sin_addr.s_addr);

   printf("\tPort number used is %d\n", myname.sin_port);

   printf("\tInternet family ID is %d\n", myname.sin_family);

   printf("\tValues are filled in after connection request ");

   printf("is accepted.");

   /* 设置初始死循环以等待客户端进程的连接请求。由于结构体myname已经和倾听套接字绑

定,通过accept()调用可以获得套接字结构名称和套接字长度参数。           */

   while (1) {

      if ( ( new_sd = accept ( sock, 0, 0 ) ) < 0 ) {

         printf("network server accept failure %d\n", errno);

         perror("network server");

         close (sock);

         exit(5);

      }

      /* 通过fork()函数建立子进程来处理客户端服务请求。*/

      if ( ( fork() ) == 0 ) {    /* 子进程 */

         int pid;

         pid = getpid();   /* 获取子进程的PID */

         close (sock); /* 子进程中不再需要父进程的参与 */

         /* 查找出客户端所在。注意通用套接字地址结构addr的用法,获取客户端信息      */



         if ((rc = getpeername( new_sd, &addr, &adrlen )) < 0) {

            printf("network server %d getpeername failure %d\n",

                 pid, errno);

            perror("network server");

            close(new_sd);

            exit(6);

         }

         /* 答应客户端信息。由于指针nptr是一个sockaddr_in结构体指针,

在这个结构体中的地址名称就可以传递给通用地址结构体addr。               */

         printf("\n\tnetwork server %d:", pid);

         printf(" client socket from host %s\n",

              inet_ntoa ( nptr -> sin_addr ) );

         printf("\t     has port number %d\n",nptr -> sin_port);

         /*	现在找到了所有与客户端相关的信息,并且可以通过在/etc/hosts

中查找来确定客户端的域名   */

         if (( hp = gethostbyaddr (&nptr -> sin_addr,4,AF_INET))

                  != NULL ) {

            printf ("\tfrom hostname: %s\n\twith aliases: ",

                   hp -> h_name );

            while ( *hp -> h_aliases )

               printf ("\n\t\t\t%s", *hp -> h_aliases++ );

            printf("\n\n");

         }

         else {

            printf("network server %d ", pid);

            printf("gethostbyaddr failure %d\n", h_errno);

            perror("network server");

         }



         /*  与客户端交换数据。首先清除缓冲区	*/



         do {

			  memset  (buf,0,sizeof(buf));  /* 清空缓冲区 */

            /* bzero( buf, sizeof(buf));* 清空缓冲区, BSD 调用. */

            /* 用read()函数从套接字缓冲区中读取远程客户端发送的数据,如果

数据长度为0则退出。*/



            if (( cnt = read (new_sd, buf, sizeof(buf))) < 0 ) {

               printf("network server %d ", pid);

               printf("socket read failure &d\n", errno);

               perror("network server");

               close(new_sd);

               exit(7);

            }

            else

            if (cnt == 0) {

               printf("network server received message");

               printf(" of length %d\n", cnt);

               printf("network server closing");

               printf(" client connection...\n");

               close (new_sd);

               continue; /* 循环终止点 */

            }

            else {



               /*  打印出接收到的信息,并发送回执       */



               printf("network server %d received message",pid);

               printf(" of length %d\n", cnt);

               printf("network server %d  received", pid);

               printf(" the message %s\n", buf);

				 memset  (buf,0,sizeof(buf));  /* 清空缓冲区 */

          	 /* bzero( buf, sizeof(buf)); * 清空缓冲区, BSD 调用. */

               strcpy(buf, "Message from server to client");

               write (new_sd, buf, sizeof(buf));

            }  /* end of message-print else */

         }  /* end of do loop  */



         while (cnt != 0);  /* 循环条件 */

         exit(0);  /* 子进程结束 */



      } /* End of if-child-process  */



      else      /* 非子进程,父进程条件判断 */

         close (new_sd); /* 父进程不需要此套接字 */



   }  /* end of while (1) */

}  /* end of main procedure */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -