zoukankan      html  css  js  c++  java
  • c--socket通信TCP篇

    程序调处来时候还是很高兴的。server向client发消息,client向server发消息。

    //s.c

     1 #include <sys/socket.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <stdio.h>
     5 #include <linux/in.h>  
     6 #include <sys/types.h>  
     7     
     8 #define PORT 7891
     9 
    10 int main()
    11 {
    12     int socketfd,accsocfd;
    13     struct sockaddr_in s_addr,r_addr;
    14     socklen_t len; 
    15     int recdata;
    16     char buf[1024];
    17     memset(buf,0x00,sizeof(buf));
    18     //创建套接字
    19     if(-1 == (socketfd = socket(AF_INET,SOCK_STREAM,0))){
    20             printf("socketfd is created failed!
    ");
    21             return -1;        
    22     }        ;    
    23      printf("socket create success!
    "); 
    24      
    25     //将本地协议地址与sockfd绑定
    26     memset(&s_addr,0x00,sizeof(s_addr));
    27     s_addr.sin_family = PF_INET;
    28     s_addr.sin_port = htons(PORT);
    29     s_addr.sin_addr.s_addr = htons(INADDR_ANY);//inet_addr_any 一个服务器可能有多个网卡,随便从中选1个
    30     if(-1 == bind(socketfd,(struct sockaddr*)&s_addr,sizeof(s_addr))){
    31         printf("bind failed!
    ");            
    32         return -1;
    33     }
    34     printf("bind suc!
    ");
    35     
    36     //监听本地端口
    37     if(-1 == listen(socketfd,10)){
    38         printf("listen failed!
    ");
    39         return -1;
    40         }
    41     printf("listen suc!
    ");
    42     
    43     while(1){
    44             len = sizeof(struct sockaddr);
    45             accsocfd = accept(socketfd,(struct sockaddr *)&r_addr,&len);
    46             if(-1 == accsocfd){
    47                     printf("accept failed!
    ");
    48                     return -1;
    49                 }
    50                 printf("accept suc !
    Server get connect from %x port is %x",ntohl(r_addr.sin_addr.s_addr),ntohl(r_addr.sin_port));
    51         
    52         
    53         //向客服端发送数据
    54         if(-1 == write(accsocfd,"this is first data from sr!
    ",50)){
    55             printf("write failed!
    ");
    56             return -1;
    57         }
    58         printf("write suc!
    ");
    59         
    60           
    61          printf("*********************
    ");
    62 
    63        char recvBuf[100];
    64  
    65     if(-1 ==recv(accsocfd, recvBuf, 100, 0)){
    66             printf("recv failed!
    ");
    67             return -1;
    68         }
    69     printf("recv suc!
    ");
    70     printf("recvBuf  = [%s]
    ",recvBuf);
    71         printf("recvBuf len is = [%d]
    ",strlen(recvBuf));
    72         
    73         close(accsocfd);
    74         
    75     }
    76     close(socketfd);
    77     return 0;
    78 }

    //c.c

    #include<sys/socket.h>
    #include<string.h>
    #include<linux/in.h>
    #include<sys/types.h>
    #include<stdio.h>
    #include<stdlib.h>
    /*流程:
    
    TCP:(面向连接、可靠)
    
    服务器端 WSAStartup->socket->bind->listen->accept->recv/send->closesocket->WSACleanup
    客户端:WSAStartup->socket->connect->recv/send->closesocket->WSACleanup
    */
    #define PORT 7891
    int main()
    {
        int csocfd;
        int recdata;    
        char buf[1024];
        memset(buf,0x00,sizeof(buf));
        struct sockaddr_in mysockaddr;
        //创建套接字
        if(-1 == (csocfd = socket(PF_INET,SOCK_STREAM,0))){
                printf("csocfd failed!
    ");
                return -1;
        }
        printf("csocfd suc!
    ");
        
        //设置服务器的地址
    
        memset(&mysockaddr,0x00,sizeof(mysockaddr));
        mysockaddr.sin_family = PF_INET;
        mysockaddr.sin_port = htons(PORT);
        inet_pton(AF_INET,"172.19.230.113",&mysockaddr.sin_addr.s_addr);
    //s_add.sin_addr.s_addr= inet_addr("172.19.230.113"); /* ip转换为4字节整形,使用时需要根据服务端ip进行更改 */  
    
    
        //connect to the sr
    if(-1 == connect(csocfd,(struct sockaddr*)&mysockaddr,sizeof(mysockaddr))){
                printf("connect failed!
    ");
                return -1;
            }
        printf("connect suc!
    ");
        
        
        if(-1 == (recdata = read(csocfd,buf,sizeof(buf)))){
                printf("read failed!
    ");
                return -1;
        }
        printf("read suc!
    ");
        buf[recdata ] = '';
        printf("recdata  = [%s]
    ",buf);
        printf("recdata len is = [%d]
    ",recdata);
        
        
        //memcpy(sendbuf,"this is data from cl!
    ",);
        if(-1 == send(csocfd, "this is data from cl!", 100, 0)){
                printf("send faile
    ");
                return -1;
            }
        printf("send suc!
    ");
        
        
        close(csocfd);
        
        
    }

    学习笔记也附上吧

    0.socket编程的目的是为了解决网络上不同主机上的进程之间通信问题
    网络中的数据传输实际上是一种I/O操作
    socket描述符可以同文件操作符进行比较,可以用read、write、close等操作,socket代表通信管道的一个端点

    1.C/S模式(以面向连接为例子)
    服务器工作过程:
    打开一个通信通道,并告诉本地主机,服务器开了一特定端口接受客服请求。
    等待客户请求。
    接收到客户请求之后发送应答信号,创建一个新线程处理请求。
    服务完成之后关闭通信通道和线程
    继续等待客户请求。
    客服端的工作过程:
    打开一通信通道,连接到服务器的制定端口。
    向服务器发送请求,并等待接受应答。
    根据需要继续发送请求
    请求结束后关闭通信信道
    2. Socket 类型常用的有2种:流式:SOCK_STREAM 数据报:SOCK_DGRAM
    主机字节序数据转换成网络字节序数据
    uint32_t htonl(uint32_t hostint32);
    uint16_t htons(uint16_t hostint16);
    网络字节序数据转换成主机字节序数据
    uint32_t ntohl(uint32_t netint32);
    uint16_t ntohs(uint16_t netint16);

    3.创建套接字
    int socket(int family, int type,intprotocol);
    功能:创建一个用于网络通信的I/O描述符(套接字)
    参数:family:协议族 AF_INET,AF_INET6,AF_LOCAL,AF_ROUTE,AF_KEY
    type: 套接字类型 套接字类型
    protocol 协议类别 0,IPPROTO_TCP,IPPROTO_UDP,IPPROTO_SCTP
    返回值:套接字
    特点:(1)使用socket创建套接字时,系统不会分配端口 (2)使用socket创建的是主动套接字,但作为服务器,
    需要被动等待别人的连接
    头文件:#include<sys/socket.h>
    示例:
    int sockfd = 0;
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if( sockfd< 0){"failed !";exit(-1);}
    4.服务器
    4.1 绑定
    int bind(int sockfd,const struct socketaddr *myaddr,socklen_t addlen);
    功能:将本地协议地址与sockfd绑定
    参数:sockfd ... myaddr:指向特定于协议的地址结构指针 addrlen:该地址结构的长度
    头文件:<sys/socket.h>
    备注: 二者的占用的内存大小是一致的,因此可以互相转化,从这个意义上说,他们并无区别。
    sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息。是一种通用的套接字地址。而sockaddr_in 是internet环境下套接字的地址形式。

    //usr/include/bits/socket.h
    struct sockaddr{
    sa_family_t sa_family; //2字节 /* 协议族 */
    char sa_data[14]; //14字节 地址+端口号*/
    };
    // sockaddr_in是在头文件 /usr/include/netinet/in.h 中定义的
    typedef uint32_t in_addr_t;
    struct in_addr{
    in_addr_t s_addr; //4字节
    };
    struct sockaddr_in{
    sa_family_t sin_family; //2字节 /* 协议族 */
    in_port_t sin_port; //2字节 /* Port number. 端口号 */
    structin_addr sin_addr; //4字节/* Internet address. IP地址 */
    unsigned char sin_zero[8]; //8字节 /* Pad to size of `struct sockaddr'. 用于填充的0字节 */
    };
    示例:
    int sockfd;
    struct sockadd_in mysock;
    sockfd = socket(AF_INET,SOCKET_STREAM,0);

    bzero(&mysock,sizeof(mysock));
    mysock.sin_family = AF_INET;
    mysock.sin_port = htons(800);
    mysock.sin_addr.saddr = inet_addr("192.168.2.45") ;
    bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr));

    //htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)
    //inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。
    //inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)
    4.2 监听
    int listen(int sockfd, int backlog);
    功能:将套接字由主动修改为被动 使操作系统为该套接字设置一个连接队列,用来记录所有连接到该套接字的连接
    参数: sockfd:socket监听套接字 sockfd:socket监听套接字
    返回值: 0 成功
    头文件: <sys/socket.h>
    示例:
    int err_log;
    err_log = listen(sockfd,10);
    4.3 从连接队列中取出一个已经建立的连接
    int accept(int sockfd,struct sockaddr*cliaddr, socklen_t*addrlen);
    功能:从已连接队列中取出一个已经建立的连接,如果没有任何连接可用,则进入睡眠等待
    参数:sockfd:socket监听套接字
    cliaddr:存放客服端套接字的地址结构,传出参数
    addrlen:套接字地址结构长度
    返回值:已连接的套接字(一个新的套接字,原先的套接字仍在监听)
    头文件: <sys/socket.h>
    示例:
    struct sockaddr_in c_addr;
    struct sockadd_in mysock;
    int sockfd;
    char buf[BUFLEN];
    int newfd;
    /*建立socket*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    bzero(&mysock,sizeof(mysock));
    mysock.sin_family = AF_INET;
    mysock.sin_port = htons(800);
    mysock.sin_addr.saddr = inet_addr("192.168.2.45") ;
    /*把地址和本地端口帮定到套接字上*/
    bind(sockfd,(struct sockaddr *)&mysock,sizeof(struct sockaddr));
    /*侦听本地端口*/
    listen(sockfd,11) ;
    while(1){
    newfd = accept(sockfd,(struct sockaddr*) &c_addr, &sizeof(c_addr));//生成一个新的套接字
    printf("当前处理的是%s: %d ",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));

    备注:accept()函数 准备好了,系统调用accept()会有点古怪的地方的!你可以想象发生 这样的事情:有人从很远的地方通过一个你在侦听 (listen()) 的端口连接 (connect()) 到你的机器。它的连接将加入到等待接受 (accept()) 的队列 中。你调用 accept() 告诉它你有空闲的连接。它将返回一个新的套接字文 件描述符!这样你就有两个套接字了,原来的一个还在侦听你的那个端口, 新的在准备发送 (send()) 和接收 ( recv()) 数据。这就是这个过程!
    5.客服端(需要知道服务器的ip及端口号)
    5.1 int connect(int sockfd,const struct sockaddr *addr,socklen_t len);
    功能:主动跟服务器建立链接,建立链接之后传送数据(tcp协议)
    部分参数说明:addr 需要链接的服务器地址结构
    返回值:0 成功
    头文件:#include <sys/socket.h>
    示例:int sockfd;
    int resCon;
    //创建套结字
    sockfd = socket(AF_INET,SOCKET_STREAM,0);
    if(sockfd <0){ ... }
    struct sockadd_in mysock;
    memset(&mysock,0x00,sizeof(mysock));
    mysock.sin_family = AF_INET;
    mysock.sin_port = htons(8999);

    mysock.sin_addr.saddr = inet_addr("192.168.2.45");
    //这里也可以用inet_pton来转换 inet_pton(AF_INET,"192.168.2.45",&mysock.sin_addr.saddr);
    //inet_pton:inet_pton 是inet_addr的扩展,将“点分十进制” -> “二进制整数”,int inet_pton(int af, const char *src, void *dst);反转inet_ntop

    //主动连接服务器
    resCon = connect(sockfd,(struct sockadd *)&mysock,sizeof(mysock));
    if(resCon){...}


    6.数据传送
    6.1 通信
    #define MAXLEN 512
    while(1){
    char send_buf[512];
    char recv_buf[512];
    memset(send_buf,0x00,sizeof(send_buf));
    memset(recv_buf,0x00,sizeof(recv_buf));

    //从流中读取MAXLEN-1个数据存入send_buf中
    fgets(send_buf,MAXLEN,stdin);

    write(sockfd,send_buf,strlen(send_buf));
    read(sockfd,recv_buf,MAXLEN);
    /*
    recv和send
      recv和send函数提供了和read和write差不多的功能.但是他们提供了第四个参数来控制读写操作。
    int recv(int sockfd,void *buf,int len,int flags)
    int send(int sockfd,void *buf,int len,int flags)
    前面的三个参数和read,write相同,第四个参数能够是0或是以下的组合

    */




    printf("recv_buf = [%s]",recv_buf);

    }

    close(sockfd);
    6.2 发送数据与接受数据
    ssize_t send(int sockfd, const void* buf,size_t nbytes, int flags);
    功能:用于发送数据,不可以用tcp发送0长度的数据
    部分参数说明;buf 待发送的数据缓存,nbytes发送的长度,flags套接字的标志,通常为0
    返回值:成功发送的字节数

    ssize_t recv(int sockfd, void *buf,size_t nbytes, int flags);
    功能:接受网络数据
    部分参数说明:buf 指向接受网络数据的缓冲区,nbytes 缓冲区的大小
    7.关闭连接
    关闭一个代表已连接套接字将导致另一端接收到一个0长度的数据包。
    做服务器时:(1)关闭socket创建的监听套接字将导致服务器无法继续接受新的连接,但不会影响已经建立的连接
    (2)关闭accept返回的已连接套接字将导致它所代表的连接被关闭,但不会影响服务器的监听




  • 相关阅读:
    Linnia学习记录
    漫漫考研路
    ENS的学习记录
    KnockoutJS 3.X API 第四章 数据绑定(4) 控制流with绑定
    KnockoutJS 3.X API 第四章 数据绑定(3) 控制流if绑定和ifnot绑定
    KnockoutJS 3.X API 第四章 数据绑定(2) 控制流foreach绑定
    KnockoutJS 3.X API 第四章 数据绑定(1) 文本及样式绑定
    KnockoutJS 3.X API 第三章 计算监控属性(5) 参考手册
    KnockoutJS 3.X API 第三章 计算监控属性(4)Pure computed observables
    KnockoutJS 3.X API 第三章 计算监控属性(3) KO如何实现依赖追踪
  • 原文地址:https://www.cnblogs.com/ashen/p/4474360.html
Copyright © 2011-2022 走看看