• Socket编程-并发服务器为例


    直接上代码,内置注解

    1.server端

      1 /**
      2     server端
      3 */
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 #include <sys/types.h>
      9 #include <sys/socket.h>
     10 #include <netinet/in.h>
     11 #include <arpa/inet.h>
     12 
     13 #define PORT 1234  //监听端口
     14 #define BACKLOG 5
     15 #define MAXDATASIZE 1000  //数据包的大小
     16 
     17 void process_cli(int  connfd, struct sockaddr_in client);
     18 
     19 int main()
     20 {
     21     int  listenfd, connfd;
     22     pid_t  pid;
     23     struct  sockaddr_in  server;
     24     struct sockaddr_in  client;
     25     int  len;
     26     /**
     27     生成一个TCP报文,PF_INET,AF_INET:ipv4网络协议,PF_INET6,AF_INET6:ipv6网络协议
     28     SOCK_STREAM提供面向连接的稳定数据传输,即TCP协议
     29     SOCK_STREAM: 提供面向连接的稳定数据传输,即TCP协议。
     30   OOB: 在所有数据传送前必须使用connect()来建立连接状态。
     31   SOCK_DGRAM: 使用不连续不可靠的数据包连接。
     32   SOCK_SEQPACKET: 提供连续可靠的数据包连接。
     33   SOCK_RAW: 提供原始网络协议存取。
     34   SOCK_RDM: 提供可靠的数据包连接。
     35   SOCK_PACKET: 与网络驱动程序直接通信
     36     **/
     37     if ((listenfd =socket(AF_INET, SOCK_STREAM, 0)) == -1) {
     38         perror("Creating socket failed.");
     39         exit(1);
     40     }
     41 
     42     int opt =SO_REUSEADDR;
     43     /**
     44     绑定在本地IP上 127.0.0.1
     45     SO_REUSEADDE 在服务器重启后,在相同的本地接口以端后上进行监听
     46     **/
     47     setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
     48     /**
     49     bzero是将数据置零,其中前一个是置零的起始地址,后一个置零的个数
     50     推荐使用memset代替 bzero
     51     **/
     52     bzero(&server,sizeof(server));
     53     //设置套接字的地址
     54     server.sin_family=AF_INET;
     55     server.sin_port=htons(PORT);
     56     server.sin_addr.s_addr= htonl (INADDR_ANY);
     57     /**
     58     该函数指明套接字将使用本地的哪一个协议端口进行数据传送(IP地址和端口号)
     59     中间的参数是通用地址,0表示成功,-1表示出错
     60     **/
     61     if (bind(listenfd,(struct sockaddr *)&server, sizeof(server)) == -1) {
     62         perror("Bind()error.");
     63         exit(1);
     64     }
     65     /**
     66     函数listen仅被服务器调用,它完成两件事:
     67         1)函数listen将未连接的套接字转化成被动套接字,指示内核应接受指向此套接字的连接请求
     68         2)函数的第二参数规定了内核为此套接字排队的最大连接个数
     69     对于给定的监听套接字,内核要维护的两个队列
     70         1)未完成连接的队列
     71         2)已完成连接的队列
     72         3)两者之和不能超过backlog
     73     */
     74     if(listen(listenfd,BACKLOG)== -1){
     75         perror("listen() error
    ");
     76         exit(1);
     77     }
     78     len=sizeof(client);
     79 
     80     while(1)
     81     {
     82         /**
     83         accept函数由TCP服务器调用,从已完成连接队列头返回下一个已完成连接;
     84         如果该队列为空,则进程进入睡眠状态
     85         函数返回的套接字为已连接套接字,应与监听套接字区分开
     86         该函数最多返回三个值,一个既可能是新套接字也可能是错误指示的整数,一个客户
     87         进程的协议地址(由cliaddr所指),以及该地址的大小(这后两个参数是值-结果参数)
     88         也就是说,服务器可以通过参数cliaddr来得到请求连接并获得成功的客户的地址和端口号
     89         */
     90     if ((connfd =accept(listenfd,(struct sockaddr *)&client,&len))==-1) {
     91         perror("accept() error
    ");
     92         exit(1);
     93     }
     94     if ((pid=fork())>0){
     95         close(connfd);
     96         continue;
     97     }else if (pid==0) {
     98         close(listenfd);
     99         process_cli(connfd, client);
    100         exit(0);
    101     }else {
    102         printf("fork()error
    ");
    103         exit(0);
    104     }
    105 }
    106     close(listenfd);
    107 }
    108 
    109 void process_cli(int connfd, struct sockaddr_in client)
    110 {
    111     int num;
    112     char  recvbuf[MAXDATASIZE], sendbuf[MAXDATASIZE], cli_name[MAXDATASIZE];
    113     printf("Yougot a connection from %s. ",inet_ntoa(client.sin_addr) );
    114     /**
    115      返回大于0表示成功接收的数据长度,0表示对方已关闭,-1出错
    116      最后一个参数:
    117         0:常规操作,如同read()函数
    118         MSG_PEEK: 只查看数据而不读出数据,后序读操作仍能读出所查看的该数据
    119         MSG_OOB:忽略常规数据,而只读带外数据
    120         MSG_WAITALL: recv 函数只有在将接收缓冲区填满后才返回
    121     **/
    122     num = recv(connfd,cli_name, MAXDATASIZE,0);
    123     if (num == 0)
    124     {
    125         close(connfd);
    126         printf("Client disconnected.
    ");
    127         return;
    128     }
    129     cli_name[num - 1] ='';
    130     printf("Client'sname is %s.
    ",cli_name);
    131 
    132     while (num =recv(connfd, recvbuf, MAXDATASIZE,0)) {
    133         recvbuf[num] ='';
    134         printf("Receivedclient( %s ) message: %s",cli_name, recvbuf);
    135         int i = 0;
    136     for (i = 0;i < num - 1; i++) {
    137         if((recvbuf[i]>='a'&&recvbuf[i]<='z')||(recvbuf[i]>='A'&&recvbuf[i]<='Z'))
    138     {
    139         recvbuf[i]=recvbuf[i]+ 3;
    140         if((recvbuf[i]>'Z'&&recvbuf[i]<='Z'+3)||(recvbuf[i]>'z'))
    141         recvbuf[i]=recvbuf[i]- 26;
    142     }
    143         sendbuf[i] =recvbuf[i];
    144     }
    145         sendbuf[num - 1]= '';
    146         /**
    147             返回:非0发送成功的数据长度,-1出错
    148             最后一个参数:
    149             0:常规操作,如同write()函数
    150             MSG_OOB,发送带外数据(TCP紧急数据)
    151             MSG_DONTROUTE:忽略底层协议的路由设置,只能将数据发送给与发送机处于在同一个网络
    152             中的机器上
    153         */
    154         send(connfd,sendbuf,strlen(sendbuf),0);
    155     }
    156         close(connfd);
    157 }
    View Code

    2.client端

     1 /**
     2     client端
     3 **/
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <unistd.h>
     7 #include <string.h>
     8 #include <sys/types.h>
     9 #include <sys/socket.h>
    10 #include <netinet/in.h>
    11 #include <netdb.h>
    12 
    13 #define PORT 1234
    14 #define MAXDATASIZE 100
    15 void process(FILE*fp, int sockfd);
    16 char *getMessage(char* sendline,int len, FILE* fp);
    17 
    18 int main(int argc,char *argv[])
    19 {
    20     int fd;
    21     struct hostent  *he;
    22     struct sockaddr_in  server;
    23     //接收IP地址
    24     if (argc !=2) {
    25         printf("Usage:%s <IP Address>
    ",argv[0]);
    26         exit(1);
    27     }
    28     //域名解析函数,注意argv[1]才是,传入的参数
    29     if((he=gethostbyname(argv[1]))==NULL){
    30         printf("gethostbyname() error
    ");
    31         exit(1);
    32     }
    33     if((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){
    34         printf("socket()error
    ");
    35         exit(1);
    36     }
    37 
    38     bzero(&server,sizeof(server));
    39     server.sin_family =AF_INET;
    40     server.sin_port=htons(PORT);
    41     server.sin_addr= *((struct in_addr *)he->h_addr);
    42     /**
    43     函数connect激发TCP的三路握手过程,仅在成功或出错返回,
    44     错误有以下几种情况:
    45         如果客户没有收到SYN分节的响应(总共75秒,之间需要可能需要重发若干次SYN)
    46         则返回ETIMEDOUT
    47         如果对客户的SYN的响应是RST,则表明该服务器主机在指定的端口上没有进程,在等待与之相连,
    48         函数返回错误ECONNREFUSED
    49         如果客户番薯的SYN在中间路由器上引发一个目的地不可达ICMP错误,客户上的内核保存此消息,
    50         并按第一种情况,连续发送SYN,直到规定时间,返回保存的消息(即ICMP错误),作为EHOSTUNREACH
    51         或ENETUNREACH错误返回给进程
    52     **/
    53     if(connect(fd,(struct sockaddr *)&server,sizeof(server))==-1){
    54         printf("connect() error
    ");
    55         exit(1);
    56     }
    57 
    58     process(stdin,fd);
    59 
    60     close(fd);
    61 }
    62 
    63 void process(FILE *fp, int  sockfd)
    64 {
    65     char sendline[MAXDATASIZE],recvline[MAXDATASIZE];
    66     int num;
    67 
    68     printf("Connected to server. 
    ");
    69     printf("Input client's name : ");
    70     //从fp指向的文件读取一个长度为num-1的字符串,存入起始地址为buf的空间,返回地址buf
    71     //若遇到文件结束或出错,返回NULL,其中fp是从标准输入读取数据
    72     if (fgets(sendline, MAXDATASIZE, fp) == NULL) {
    73         printf("
    Exit.
    ");
    74         return;
    75     }
    76     send(sockfd,sendline, strlen(sendline),0);
    77     while(getMessage(sendline, MAXDATASIZE, fp) != NULL) {
    78     send(sockfd,sendline, strlen(sendline),0);
    79 
    80     if ((num =recv(sockfd, recvline, MAXDATASIZE,0)) == 0) {
    81         printf("Server terminated.
    ");
    82         return;
    83     }
    84 
    85     recvline[num]='';
    86     printf("Server Message: %s
    ",recvline);
    87 
    88 }
    89     printf("
    Exit.
    ");
    90 }
    91 
    92 char  *getMessage(char*  sendline,int len, FILE*  fp)
    93 {
    94     printf("Inputstring to server:");
    95     return(fgets(sendline,MAXDATASIZE, fp));
    96 }
    View Code

    参考

    1:参考一

    2:参考二

  • 相关阅读:
    定位及CSS常见属性
    浮动及清浮动的方法
    C语言II博客作业04
    C语言II—作业03
    C语言II—作业02
    C语言II博客作业01
    期末总结
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
  • 原文地址:https://www.cnblogs.com/sxmcACM/p/4060369.html
Copyright © 2020-2023  润新知