zoukankan      html  css  js  c++  java
  • socket详解

    socket网络编程
    1.进程间如何通信
    本地进程间通信我们知道有以下几种方式:
    1)消息传递(管道,FIFO,消息队列)
    管道是一个进程的数据流到另一个进程的通道,即一个进程的数据输出作为另一个进程的数据输入,管道起到了桥梁的作用。
    2)共享内存
    不同进程访问同一个逻辑内存
    3)同步
    互斥量,条件变量,读写锁,信号量
    4)远程过程调用
    但是网络间的进程是如何通信的呢?如浏览器进程如何与web服务器通信,QQ聊天时,QQ进程如何与服务器或你好友所在的QQ进程通信?
    答案是socket,网络间的进程通信几乎都是用的socket.

    2.如何识别网络中唯一进程
    本地进程间可以通过PID来唯一标识一个进程
    网络中我们根据TCP/IP协议族来标识唯一进程,网络层的“IP地址”可唯一标识网络中的主机,而传输层的“协议+端口”可唯一标识主机中的进程。“IP地址+协议+端口”就可以确定唯一进程了。
    3.进程间如何通过socket进行通讯
    Linux的哲学是一切皆文件,socket也是一种文件。可以使用“打开-读写-关闭”来操作。socket是应用层和运输层之间的一个抽象层。
    socket通信流程:
    1)服务端创建socket
    socket()
    2)服务端绑定端口号
    bind()
    3)服务端监听端口号
    listen()
    4)客户端创建socket
    socket()
    5)客户端主动打开socket,连接服务器端socket
    connect()
    6)服务端接收客户端请求,socket被动打开
    同步:accept() 异步:beginaccept()
    7)客户端socket向服务端socket写信息
    send()
    8)服务端socket读取信息
    9)客户端socket关闭
    10)服务端socket关闭

    4.socket建立连接的三次握手

    第一步,客户端调用connect,向服务器发送SYN J包,connect阻塞
    第二步,服务端收到SYN J包,调用accept函数接收请求,向客户端发送 SYN K,ACK J+1
            accept函数阻塞
    第三步,客户端收到服务器的SYN K,ACK J+1后,connect返回,进行SYN K确认,服务端收到ACK K+1时,accept返回,三次握手完成,连接建立。

    5.socket释放连接的四次握手


    第一步,客户端关闭连接,发送一个FIN M到服务端
    第二步,服务端接收到FIN M后,执行被动关闭,对这个FIN M进行确认ACK M+1。
    第三步,当服务端发送完毕后,再发送FIN N到客户端
    第四步,客户端接收到FIN N调用close关闭它的socket,发送一个ACK N+1到服务端
    服务端接收到这个ACK N+1关闭它的socket

    6.为什么建立连接是三次握手,释放连接需要四次
    这是因为进行释放连接的第二步时,有可能服务端仍有数据发送给客户端,因此,需要分开,先对客户端FIN报文应答,当服务端数据发送完毕后,再发送FIN报文到客户端。

    7.socket连接示例
    服务器端

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    
    #define MAXLINE 4096
    
    int main(int argc, char** argv)
    {
        int    listenfd, connfd;
        struct sockaddr_in     servaddr;
        char    buff[4096];
        int     n;
    
        if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
        printf("create socket error: %s(errno: %d)
    ",strerror(errno),errno);
        exit(0);
        }
    
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(6666);
    
        if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
        printf("bind socket error: %s(errno: %d)
    ",strerror(errno),errno);
        exit(0);
        }
    
        if( listen(listenfd, 10) == -1){
        printf("listen socket error: %s(errno: %d)
    ",strerror(errno),errno);
        exit(0);
        }
    
        printf("======waiting for client's request======
    ");
        while(1){
        if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
        n = recv(connfd, buff, MAXLINE, 0);
        buff[n] = '';
        printf("recv msg from client: %s
    ", buff);
        close(connfd);
        }
    
        close(listenfd);
    }

    客户端

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    
    #define MAXLINE 4096
    
    int main(int argc, char** argv)
    {
        int    sockfd, n;
        char    recvline[4096], sendline[4096];
        struct sockaddr_in    servaddr;
    
        if( argc != 2){
        printf("usage: ./client <ipaddress>
    ");
        exit(0);
        }
    
        if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)
    ", strerror(errno),errno);
        exit(0);
        }
    
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(6666);
        if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
        printf("inet_pton error for %s
    ",argv[1]);
        exit(0);
        }
    
        if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
        printf("connect error: %s(errno: %d)
    ",strerror(errno),errno);
        exit(0);
        }
    
        printf("send msg to server: 
    ");
        fgets(sendline, 4096, stdin);
        if( send(sockfd, sendline, strlen(sendline), 0) < 0)
        {
        printf("send msg error: %s(errno: %d)
    ", strerror(errno), errno);
        exit(0);
        }
    
        close(sockfd);
        exit(0);
    }
  • 相关阅读:
    Linux虚拟内存管理(glibc)
    linux kernel内存回收机制
    Linux的Cache Memory(缓存内存)机制
    imx6用文件io操作gpio
    imx6中iomux IO复用
    start with git
    Linux进程的虚拟内存区域划分
    关于函数返回值为指针类型的分析
    对LCD接口的认识
    LCD屏背光驱动调试心得---血的教训
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/6127440.html
Copyright © 2011-2022 走看看