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返回的已连接套接字将导致它所代表的连接被关闭,但不会影响服务器的监听




  • 相关阅读:
    linux故障分析简介
    egon说一切皆对象--------面向对象进阶紫禁之巅
    alex说:一切皆bytes
    数据类型小结
    继续死磕python
    python初步学习
    初识python
    3.17内存,进程,rpm和yum,python编译安装
    用户权限(3.15)
    操作系统和基础网络知识
  • 原文地址:https://www.cnblogs.com/ashen/p/4474360.html
Copyright © 2011-2022 走看看