zoukankan      html  css  js  c++  java
  • 网络编程之套接字(tcp)

      经过几天高强度的学习,对套接字的编程有了初步的认识,今天对这几天所学的知识总结一下;首先简单阐述一下tcp通信;

      TCP提供的是可靠的,顺序的,以及不会重复的数据传输,处理流控制,由于TCP是可靠的,连接的,顺序的,所以TCP一般用于都应用于对传输的完整性,正确性要求严的场合;编写基于tcp的服务器-客户端模型的程序简单流程如下:

      服务器端:

      (1)调用socket()创建一个套接口

      (2)调用bind()函数是服务器进程与一个端口绑定

      (3)调用listen()设置客户接入队列的大小

      (4)调用accept()接受一个连接,如果介入的队列不为空,则返回一个已连接的套接口描述符,

      (5)调用sned()和recv()函数用来在已连接的套接口间进行发送和接收数据

      客户端:

      (1)调用socket()创建套接字

      (2)调用connect()函数向服务器发送连接请求;

      (3)调用send()函数和recv()函数

      下面是服务器端的代码;

     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 
     5 //server
     6 int main()
     7 {
     8     int fd = 0;
     9     int nfd = 0;
    10     int ret = 0;
    11     unsigned char data[1024] = {0};
    12 
    13     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    14     if(fd < 0) {
    15         perror("socket");
    16         return 1;
    17     }
    18     /*服务端信息*/
    19     struct sockaddr_in ser;
    20     ser.sin_family = AF_INET;
    21     ser.sin_port = htons(2009);
    22     ser.sin_addr.s_addr = htonl(0xc0a8010a);//192.168.1.10
    23     struct sockaddr_in clt;
    24     int len = 0;
    25 
    26     /*绑定*/
    27     ret = bind(fd, (struct sockaddr *)&ser, 16);
    28     if(ret < 0) {
    29         perror("bind");
    30         return 1;
    31     }
    32 
    33     /*监听*/
    34     ret = listen(fd, 10);
    35     if(ret == -1) {
    36         perror("listen");
    37         return 1;
    38     }
    39 
    40     /*接收连接,并且返回一个新的套接字描述符nfd*/
    41     nfd = accept(fd, (struct sockaddr *)&clt, &len);
    42     if(ret < 0) {
    43         perror("accept");
    44         return 1;
    45     }
    46     
    47     /*接收*/    
    48     ret = recv(nfd, data, 1024, 0);
    49     if(ret < 0) {
    50         perror("recv");
    51         return 1;
    52     }
    53     printf("clt said: %s
    ", data);
    54     close(fd);
    55     
    56     return 0;
    57 }
    服务器端
     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <string.h>
     5 
     6 //client
     7 int main()
     8 {
     9     int sock_fd = 0;
    10     int ret = 0;
    11     unsigned char *buf = "hello, hao ara you";
    12 
    13     /*创建一个套接口*/    
    14     sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    15     if(sock_fd < 0) {
    16         perror("socket");
    17         return 1;
    18     }
    19     
    20     /*服务端信息*/
    21     struct sockaddr_in ser;
    22     ser.sin_family = AF_INET;
    23     ser.sin_port = htons(2009);
    24     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
    25 
    26     //建立链接
    27     ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
    28     if(ret < 0) {
    29         perror("connect");
    30         return 1;
    31     }
    32 
    33     /*发送*/
    34     ret = send(sock_fd, buf, strlen(buf), 0);
    35     if(ret < 0) {
    36         perror("send");
    37         return 1;
    38     }
    39 
    40     close(sock_fd);    
    41     return 0;        
    42 }
    客户端

    上面程序是基于tcp的简单通信,下面我们利用tcp实现一个服务器多个客户机;要实现一对多,就要使用线程编程,服务器端在不断监听中,如果有连接请求的话,就用通过 accept函数接受并创建一个线程来处理。线程的创建函数为int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg);

      下面是这个程序的源码

     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <string.h>
     5 #include <pthread.h>
     6 
     7 #define PORT 9527
     8 
     9 void *function(void *d);//线程要执行的函数
    10 
    11 int main()
    12 {
    13     /*创建套接口*/
    14     pthread_t pid= 0;
    15     int nfd = 0; 
    16     int fd = 0;
    17     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    18     if(fd < 0) {
    19         perror("sock");
    20         return 1;
    21     }
    22     /*服务器信息*/
    23     struct sockaddr_in ser;
    24     ser.sin_family = AF_INET;
    25     ser.sin_port = htons(PORT);
    26     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
    27     struct sockaddr_in clt;
    28     int len = 0;
    29 
    30     /*绑定*/
    31     int ret = bind(fd, (struct sockaddr *)&ser, 16);
    32     if(ret == -1) {
    33         perror("bind");
    34         return 1;
    35     }
    36 
    37     /*监听*/
    38     ret = listen(fd, 10);
    39     if(ret < 0) {
    40         perror("listen");
    41         return 1;
    42     }
    43 
    44     while(1) {
    45         /*接受链接*/
    46         nfd = accept(fd, (struct sockaddr *)&clt, &len);
    47         if(nfd < 0) {
    48             perror("accept");
    49             return 1;
    50         }
    51 
    52         /*创建一个线程*/        
    53         ret = pthread_create(&pid, NULL, function, (void *)nfd);    
    54         if(ret != 0) {
    55             perror("pthread_create");
    56             return 1;
    57         }
    58 
    59         pthread_join(pid, NULL);
    60 
    61         close(nfd);
    62     }
    63      
    64     close(fd);
    65     return 0;    
    66 }
    67 
    68 void *function(void *d)
    69 {    
    70     unsigned char buf[1024] = {0};
    71     int nfd = (int )d;
    72     int ret = 0;
    73         
    74     memset(buf, 0, 1024);
    75     ret = recv(nfd, buf, 1024, 0);
    76     if(ret < 0) {
    77         perror("recv");
    78         return NULL;
    79     }
    80     printf("client said: %s
    ", buf);
    81 
    82     ret = send(nfd, "recv ok", 7, 0);
    83     if(ret < 0) {
    84         perror("send");
    85         return NULL;
    86     }
    87 
    88     
    89 }
    server
     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <string.h>
     5 
     6 #define PORT 9527
     7 
     8 int main(int argc, char **argv)
     9 {
    10     if(argc != 3) {
    11         printf("using %s <ip address> <message>
    ", argv[0]);
    12         return 0;
    13     }
    14     /*创建套接口*/
    15     int fd = 0;
    16     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    17     if(fd < 0) {
    18         perror("socket");
    19         return 1;    
    20     }
    21 
    22     /*服务器信息*/
    23     struct sockaddr_in ser;
    24     ser.sin_family = AF_INET;
    25     ser.sin_port = htons(PORT);
    26     ser.sin_addr.s_addr = inet_addr(argv[1]);
    27 
    28     /*创建链接*/
    29     int ret = connect(fd, (struct sockaddr *)&ser, 16);
    30     if(ret < 0) {
    31         perror("connect");
    32         return 1;
    33     }        
    34     
    35     /*访问*/
    36     ret = send(fd, argv[2], strlen(argv[2]), 0);
    37     if(ret < 0) {
    38         perror("send");
    39         return 1;
    40     }
    41     
    42     char buf[1024] = {0};
    43     ret = recv(fd, buf, 1024, 0);
    44     if(ret < 0) {
    45         perror("recv");
    46         return 1;
    47     }    
    48     printf("server: %s
    ", buf);
    49     close(fd);
    50 
    51     return 0;            
    52 }
    client

      上面代码需要注意的是,监听程序最大允许接受10个连接请求,如果这十个一直连接不断开的话,后续的连接请求就无法得到处理,所以我们需要在每次请求完毕之后就关闭nfd;下次请求再重新连接;

      第三个程序我们实现基于tcp的聊天程序:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<sys/socket.h>
     5 #include<netinet/in.h>
     6 
     7 int main()
     8 {
     9     /*创建套接口*/
    10     int  fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    11     if(fd < 0){
    12         perror("socket");
    13         exit(EXIT_FAILURE);
    14     }
    15     
    16     /*服务端信息*/
    17     struct sockaddr_in srv;
    18     srv.sin_family = AF_INET;
    19     srv.sin_port=htons(9527);
    20     srv.sin_addr.s_addr = htonl(INADDR_ANY);
    21 
    22     /*绑定*/
    23     int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
    24     if(ret < 0){
    25         perror("bind");
    26         exit(EXIT_FAILURE);
    27     }
    28     ret = listen(fd,10);
    29     if(ret < 0){
    30         perror("bind");
    31         exit(EXIT_FAILURE);
    32     }
    33     struct sockaddr_in snd;
    34     int snd_len = 0;
    35 
    36     /*接受*/
    37     int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
    38     if(nfd < 0){
    39         perror("accpet");
    40         exit(EXIT_FAILURE);
    41     }
    42 
    43     char data[1024] = {0};
    44     char revdata[1024] = {0};
    45     /*聊天*/
    46     while(1){
    47         memset(revdata, 0, 1024);    
    48         memset(data, 0, 1024);         
    49         ret = recv(nfd,revdata,1024,0);
    50             if(ret < 0){
    51               perror("recv");
    52               exit(EXIT_FAILURE);
    53            }
    54            
    55         printf("client say: %s
    ",revdata);
    56         if(strcmp(revdata, "end") == 0) {
    57             break;
    58         }
    59 
    60         ret = read(0,data,1024);
    61            if(ret < 0){
    62             perror("read");
    63             exit(EXIT_FAILURE);
    64         }
    65         ret = send(nfd,data,1024,0);
    66         if(ret < 0){
    67             perror("recv");
    68             exit(EXIT_FAILURE);
    69         }
    70         
    71         
    72     }    
    73     close(nfd);
    74     close(fd);
    75     return 0;
    76 }
    server
     1 #include <stdio.h>
     2 #include <sys/socket.h>
     3 #include <netinet/in.h>
     4 #include <string.h>
     5 #include <sys/types.h>
     6 #include <unistd.h>
     7 
     8 int main()
     9 {
    10     /*创建套接口*/
    11     int sock_fd = 0;
    12     sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    13     if(sock_fd < 0) {
    14         perror("socket");
    15         return 1;
    16     }
    17     /*服务端信息*/
    18     struct sockaddr_in ser;
    19     ser.sin_family = AF_INET;
    20     ser.sin_port = htons(9527);
    21     ser.sin_addr.s_addr = inet_addr("192.168.1.10");
    22 
    23     /*建立链接*/
    24     int ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
    25     if(ret == -1) {
    26         perror("connect");
    27         return 1;
    28     }
    29 
    30     /*聊天*/
    31     unsigned char data[1024] = {0};
    32     unsigned char rec[1024] = {0};
    33     while(1) {    
    34         memset(data, 0, 1024);
    35         memset(rec, 0, 1024);
    36         int r_size = read(0, data, 1024);
    37         if(r_size < 0) {
    38             perror("read");
    39             return 1;
    40         }
    41 
    42         ret = send(sock_fd, data, strlen(data), 0);
    43         if(ret < 0) {
    44             perror("send");
    45             return 1;
    46         }
    47         
    48         ret = recv(sock_fd, rec, 1024, 0);
    49         if(ret < 0) {
    50             perror("recv");
    51             return 1;
    52         }
    53         printf("server said: %s
    ", rec);
    54     }
    55     close(sock_fd);    
    56     return 0;
    57 }
    client

    上面这个代码存在的缺陷是,发送方跟接收只能发送一句接收一句,不能一次性发送多句,要解决这个问题就要需用到IO多路服用,可以通过这个函数来实现:
      int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);

    下面贴出代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<sys/socket.h>
     5 #include<netinet/in.h>
     6 
     7 int main()
     8 {
     9     /*创建套接口*/
    10     int  fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    11     if(fd < 0){
    12         perror("socket");
    13         exit(EXIT_FAILURE);
    14     }
    15     
    16     /*服务端信息*/
    17     struct sockaddr_in srv;
    18     srv.sin_family = AF_INET;
    19     srv.sin_port=htons(9527);
    20     srv.sin_addr.s_addr = htonl(INADDR_ANY);
    21 
    22     /*绑定*/
    23     int ret = bind(fd,(struct sockaddr *)&srv,sizeof(struct sockaddr ));
    24     if(ret < 0){
    25         perror("bind");
    26         exit(EXIT_FAILURE);
    27     }
    28     ret = listen(fd,10);
    29     if(ret < 0){
    30         perror("bind");
    31         exit(EXIT_FAILURE);
    32     }
    33     struct sockaddr_in snd;
    34     int snd_len = 0;
    35 
    36     /*接受*/
    37     int nfd = accept(fd,(struct sockaddr *)&snd,&snd_len);
    38     if(nfd < 0){
    39         perror("accpet");
    40         exit(EXIT_FAILURE);
    41     }
    42 
    43     fd_set rfds;    
    44     char data[1024] = {0};
    45     char revdata[1024] = {0};
    46     /*聊天*/
    47     while(1){
    48 
    49         FD_ZERO(&rfds);
    50         FD_SET(0,&rfds);
    51         FD_SET(nfd,&rfds);
    52         ret = select(nfd+1,&rfds,NULL,NULL,NULL);
    53         if(FD_ISSET(nfd, &rfds)){
    54               ret = recv(nfd,revdata,1024,0);
    55                 if(ret < 0){
    56                     perror("recv");
    57                    exit(EXIT_FAILURE);
    58                 }
    59                 
    60             printf("client say: %s
    ",revdata);
    61             if(strcmp(revdata, "end") == 0) {
    62                 break;
    63             }
    64         }
    65         if(FD_ISSET(0, &rfds)) {
    66             ret = read(0,data,1024);
    67                if(ret < 0){
    68                 perror("read");
    69                 exit(EXIT_FAILURE);
    70             }
    71             ret = send(nfd,data,1024,0);
    72             if(ret < 0){
    73                 perror("recv");
    74                 exit(EXIT_FAILURE);
    75             }
    76         }
    77         memset(revdata, 0, 1024);
    78         memset(data, 0, 1024);
    79     }    
    80     close(nfd);
    81     close(fd);
    82     return 0;
    83 }
    server
    #include <stdio.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
        /*创建套接口*/
        int sock_fd = 0;
        sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(sock_fd < 0) {
            perror("socket");
            return 1;
        }
        /*服务端信息*/
        struct sockaddr_in ser;
        ser.sin_family = AF_INET;
        ser.sin_port = htons(9527);
        ser.sin_addr.s_addr = inet_addr("192.168.1.10");
    
        /*建立链接*/
        int ret = connect(sock_fd, (struct sockaddr *)&ser, 16);
        if(ret == -1) {
            perror("connect");
            return 1;
        }
    
        /*聊天*/
        fd_set rfds;    
        unsigned char data[1024] = {0};
        unsigned char rec[1024] = {0};
        while(1) {    
            memset(data, 0, 1024);
            memset(rec, 0, 1024);
            FD_ZERO(&rfds); //清空
            FD_SET(0,&rfds);//(标准输入)
            FD_SET(sock_fd,&rfds);//添加监听描述符(套接字)
            /*多路复用IO*/
            ret = select(sock_fd+1,&rfds,NULL,NULL,NULL);
    
            if(FD_ISSET(0, &rfds)){//监听键盘是否有输入,执行接收
                int r_size = read(0, data, 1024);
                if(r_size < 0) {
                    perror("read");
                    return 1;
                }
                ret = send(sock_fd, data, strlen(data), 0);
                if(ret < 0) {
                    perror("send");
                    return 1;
                }
            }
            
            if(FD_ISSET(sock_fd, &rfds)) {//监听sock_fd是否有输入,执行接收
                ret = recv(sock_fd, rec, 1024, 0);
                if(ret < 0) {
                    perror("recv");
                    return 1;
                }
                printf("server said: %s
    ", rec);
            }
        }
        close(sock_fd);    
        return 0;
    }
    client

        

      

  • 相关阅读:
    git 远程仓库的使用
    git 以及 工作区 版本库 暂存区
    git repo gerrit 的关系
    【转】c# delegate
    【转】分析.net中的object sender与EventArgs e
    如果plsql连接没问题,但程序中报ORA-12504的错误
    【转】C# String 与 Char[] 数组 相互转换
    【转】C#日期时间格式化
    PLSQL导出语句的查询结果
    oracle取order by的第一条数据
  • 原文地址:https://www.cnblogs.com/wenqiang/p/4766956.html
Copyright © 2011-2022 走看看