C/C++知识点之c语言中如何实现网络通信(流程实例)
小标 2018-08-27 来源 : 阅读 1124 评论 0

摘要:本文主要向大家介绍了C/C++知识点之c语言中如何实现网络通信(流程实例),通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了C/C++知识点之c语言中如何实现网络通信(流程实例),通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

主要函数:

------------------------------------------

TCP实现服务器与客户端的通信流程

//服务器端---服务器是一个被动的角色

1.socket          //买一个手机

2.bind            //SIM卡 绑定一个手机号(ip+port)

3.listen          //待机(等待电话打入)

4.accept          //接听电话

5.read/write      //通话

6.close           //挂机

//客户端---客户端是一个主动发起请求的一端

1.socket           //买一个手机

2.bind(可选的)     //SIM卡(绑定号码)

3.connect          //拨打电话

4.read/write       //通话

5.close            //挂机

//1.socket  ---- 插口 

int socket(int domain, int type, int protocol);

功能:  创建通信的一端 (socket)

参数:

    @domain    //"域" --范围

               AF_INET  //IPV4 协议的通信

    @type      SOCK_STREAM //TCP (流式套接字)

    @protocol  0           //LINUX下 流式套接字 ==>TCP

              //协议 

返回值:

   成功 对应的socket文件描述符

   失败 返回-1 

注意:

文件描述符:

   实际上就是 创建好的 socket的一个标识符

//2.bind 

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

功能:

    给指定的 socket 绑定地址信息

参数:

   @sockfd    //表示操作的socket

   @addr      //填充的地址信息(ip + port)

   @addrlen   //地址信息结构体的大小

返回值:

   成功 0

   失败 -1

   //通用的地址结构

   struct sockaddr {

       sa_family_t sa_family; //AF_INET //IPV4的协议

       char       sa_data[14];//(ip+port)

   }

//网络通信的地址结构(internet)

struct sockaddr_in {

    sa_family_t    sin_family; /* address family: AF_INET */

    in_port_t      sin_port;   /* port in network byte order */

    struct in_addr sin_addr;   /* internet address */

};

/* Internet address. */

struct in_addr {

    uint32_t       s_addr;      /* address in network byte order */

};

//1.定义一个 地址结构体变量

struct sockaddr_in addr;

bzero(&addr,sizeof(addr)); //清0的函数

//2.之后进行信息填充

addr.sin_family = AF_INET;

addr.sin_port = htons(8888);

addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 

                     //127.0.0.1 是回环测试的地址

//3.进行绑定

if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)

{

    perror("bind fail");

    return 0;

}

//3.listen  --- 设置监听 ---作用:让操作系统监控是否有客户端发起连接

int listen(int sockfd, int backlog);

功能:

   设置监听 

参数:

   @sockfd    //监听套接字

   @backlog   //监听队列的大小

返回值

   成功 0

   失败 -1

   listenfd 

--------------监听队列------------------

fd1 fd2 fd3 fd4

 |

-|--------------------------------------

 |

 \---->建立好连接的套接字 

       accept函数获取已连接的套接字 返回对应

       的标识符 

         |--->后面的读写操作 都是通过这个标识符

              进行的

-----------------------------------------------

accept(); //accept 从监听队列中获得已连接的的socket,返回一个标示符来表示已连接的socket

          //后续通过已连接的socket进行通信

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

功能: 获取连接

参数:

   @sockfd    //监听套接字的fd(标识符)

   @addr     //来电显示(保存对端的地址信息)(ip+port)

   @addrlen  //表示 addr 参数对应类型的大小,值结果参数 --- 就是在用的时候,必须先赋一个初值,最后函数调用完成

             //通过该参数,返回一个结果值

返回值:

   成功 已连接的socket的标识符

   失败 -1

//connect ---发起连接

   int connect(

       int sockfd,  //表示 进行通信的 socket的标识符

       const struct sockaddr *addr, //对端的地址信息(ip+port)

       socklen_t addrlen); //表示的是 addr 参数类型的长度

       

      参数:

        @sockfd   //通过socket函数获得的fd

        @addr     //服务器端的地址

        @addrlen  //参数addr类型的大小 

//数据流向  fd --> buf (count 表示一次读取多少个字节)

ssize_t read(int fd, void *buf, size_t count);

//数据流向  buf--> fd (count 表示一次写多少个字节)

ssize_t    write(int  fd,    const  void  *buf, size_t count);

参数:

   @fd 就是要操作的 socket对应的 标示符

   @buf 保存数据的一块内存首地址

   @count 一次操作的字节数

confd 

char buf[] = "hello QCXY\n";

write(confd,buf,strlen(buf)); //写 数据到socket中

//读数据出来

char rbuf[1024] = {0}; //表示申请了一块1024个字节大小

                       //的内存空间

read(confd,rbuf,sizeof(rbuf)); //读取数据

//练习:

实现 客户端 向服务器发送数据

服务器回发数据的功能

client       -----        server

 scanf();  ---(1)---->        read 之后printf

  read     <--(2)----         write

  printf

  

  循环做,结束条件

  当客户端输入 "quit"字符串时 客户端结束

  怎么判断客户端读到的是"quit"

  

 c语言中

 "quit" == buf; (X) //不能这么写

//字符串的比较函数

 strcmp("quit",buf);

 strncmp("quit",buf,4);

客户端的程序:

#include <stdio.h>

#include <sys/types.h>           /* See NOTES */

#include <sys/socket.h>

#include <strings.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <string.h>

//./client 127.0.0.1 8888 

int main(int argc, const char *argv[])

{

    int fd;

    int ret = 0;

    char buf[1024] = {0};

    char rbuf[1024] = {0};

    //处理命令行参数

    //1.socket(手机)

    //2.bind(电话卡)

    //3.connect (拨打电话)

    

    //处理命令行参数

    if(argc != 3)

    {

        printf("Usage: %s <ip> <port>\n",argv[0]);

        return -1;

    }

    //1.socket(手机)

    fd = socket(AF_INET,SOCK_STREAM,0);

    if(fd < 0) //出错处理

    {

        perror("socket fail");

        return -1;

    }

    printf("fd = %d\n",fd);

    //2.bind(电话卡)---绑定的是客户端自己的地址信息

   

     //客户端地址信息

    //1.定义一个 地址结构体变量

    struct sockaddr_in cli_addr;

    bzero(&cli_addr,sizeof(cli_addr)); //清0的函数

    //2.之后进行信息填充

    cli_addr.sin_family = AF_INET;

    cli_addr.sin_port = htons(7777);

    cli_addr.sin_addr.s_addr = inet_addr(argv[1]);

    if(bind(fd,(struct sockaddr*)&cli_addr,sizeof(cli_addr)) < 0)

    {

        perror("bind fail");

        return -1;

    }

    //服务器端的地址信息

    //1.定义一个 地址结构体变量

    struct sockaddr_in addr;

    bzero(&addr,sizeof(addr)); //清0的函数

    //2.之后进行信息填充

    addr.sin_family = AF_INET;

    addr.sin_port = htons(atoi(argv[2]));

    addr.sin_addr.s_addr = inet_addr(argv[1]); 

    //3.connect (拨打电话)

    if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))<0)

    {

        perror("connect fail");

        return -1;

    }

    printf("connect success\n");

   //通信过程

    while(1)

    {

     //客户端从键盘获得数据 

     //数据流向stdin --> buf

     fgets(buf,sizeof(buf),stdin); //stdin表示是从键盘获得数据

     //发送给服务器

     write(fd,buf,strlen(buf));

     //接受服务器回发的消息

     ret = read(fd,rbuf,sizeof(rbuf));

     //如果回发的消息是

     //quit 

     //则结束

     rbuf[ret] = '\0';

     printf("rbuf = %s\n",rbuf);

     

     if(strncmp("quit",buf,4) == 0)

     {

         close(fd);

         break;

     }

    }

    return 0;

}

服务端

#include <stdio.h>

#include <sys/types.h>           /* See NOTES */

#include <sys/socket.h>

#include <strings.h>

#include <netinet/in.h>

#include <arpa/inet.h>

//./server 127.0.0.1 8888

int main(int argc, const char *argv[])

{

    int fd = 0;

    int connfd = 0;

    int ret = 0; 

    char buf[1024] = {0};

    //处理命令行参数

    if(argc != 3)

    {

        printf("Usage: %s <ip> <port>\n",argv[0]);

        return -1;

    }

    //1.socket 创建套接字

    fd = socket(AF_INET,SOCK_STREAM,0);

    if(fd < 0) //出错处理

    {

        perror("socket fail");

        return -1;

    }

    printf("fd = %d\n",fd);

    //2.绑定

    //1.准备地址信息

    //2.绑定

    //

    //1.定义一个 地址结构体变量

    struct sockaddr_in addr;

    bzero(&addr,sizeof(addr)); //清0的函数

    //2.之后进行信息填充

    addr.sin_family = AF_INET;

    addr.sin_port = htons(atoi(argv[2]));

    addr.sin_addr.s_addr = inet_addr(argv[1]); 

    //127.0.0.1 是回环测试的地址

    //3.进行绑定

    if(bind(fd,(struct sockaddr*)&addr,sizeof(addr)) < 0)

    {

        perror("bind fail");

        return 0;

    }

    printf("bind success\n");

    //4.设置监听

    if(listen(fd,5) < 0)

    {

        perror("listen fail");

        return -1;

    }

    struct sockaddr_in peer_addr;

    socklen_t addrlen = sizeof(peer_addr); 

    //5.获取连接 -- 接听电话

    while(1) //可以不断接受客户端的请求

    {

        //connfd =  accept(fd,NULL,NULL);

        connfd =  accept(fd,(struct sockaddr*)&peer_addr,&addrlen);

        if(connfd < 0)

        {

            perror("accept fail");

            return -1;

        }

        printf("connfd = %d\n",connfd);

        printf("-----------------------\n");

        printf("ip = %s\n",inet_ntoa(peer_addr.sin_addr));

        printf("port = %d\n",ntohs(peer_addr.sin_port));

        printf("-----------------------\n");

      //通信过程

      //效果实现数据回发

        while(1)

        {

            //read 与 write 的返回值 大于0 时表示的是

            //一次成功操作到的字节数

            ret = read(connfd,buf,sizeof(buf));

            //hello

            buf[ret] = '\0'; //添加'\0'--转换成字符串

            printf("buf = %s\n",buf);//字符串打印 需要

                                     //结束标志 '\0'

            if(ret == 0 || strncmp(buf,"quit",4) == 0)

            {

                close(connfd);

                break;

            }

            write(connfd,buf,ret);

        }

    

    } //telnet <ip> <port>

    return 0;

}

补充:

可以用如下函数替代read,write

     ssize_t recv(int sockfd,  void* buf,size_t len,int flags);

    ssize_t send(int sockfd,const void *buf,size_t len,int flags);

     @sockfd //进行操作的socket的文件描述符

     @buf    //保存数据的首地址

     @len    //一次操作的字节数

     @flags   //标志0--默认的操作方式(阻塞)

返回值:

      成功  成功操作的字节数

     失败   -1&errno    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程