精华内容
下载资源
问答
  • 套接字编程
    千次阅读
    2019-09-15 21:02:34

    套接字

    *套接字:套接字是一个抽象层,是传输层实现端与端的通信,每一个传输层连接有两个端点,传输层连接的端点叫做套接字。套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。
    *tcp套接字编程: 以字节流方式传输数据,实现tcp网络传输方案。(面向连接–tcp协 议–可靠的–流式套接字)的编程
    python代码实现:

    """
    tcp_server.py  tcp套接字服务端流程
    
    """
    #导入模块
    import socket
    
    # 创建tcp套接字对象
    sockfd = socket.socket(socket.AF_INET,
                           socket.SOCK_STREAM)
    
    # 绑定地址
    sockfd.bind(('0.0.0.0',9999))
    
    # 设置监听
    sockfd.listen(5)
    
    # 等待处理客户端连接请求
    while True:
        print("Waiting for connect...")
        try:
            connfd,addr = sockfd.accept()
            print("Connect from",addr)
        except KeyboardInterrupt:
            # ctrl-c 退出程序
            print("Server exit")
            break
        except Exception as e:
            print(e)
            continue
    
        #循环 消息收发
        while True:
            data = connfd.recv(1024)  #接收消息字节数
            # 如果data为空意味着客户端断开
            if not data:
                break
            print("Receive:",data.decode())
            # if data == b'Q':
            #     break
            n = connfd.send(b"Thanks") #传输数据转化为二进制
            print('Send %d bytes'%n)
        connfd.close()
    
    
    # 关闭套接字
    sockfd.close()
    
    
    

    客户端:

    """
    tcp_client.py  tcp套接字客户端流程
    注意: 和服务端配合,使用同样的套接字
    """
    
    from socket import *
    
    # 创建tcp套接字
    sockfd = socket() # 默认值
    
    # 连接服务器
    server_addr = ('127.0.0.1',9999) # 服务器地址
    sockfd.connect(server_addr)
    
    # 先发后收
    while True:
        msg = input("Msg:")
        if not msg:
            break
        sockfd.send(msg.encode()) #字节串
        # if msg == 'Q':
        #     break
        data = sockfd.recv(1024)#设置接收的消息的最大字节数
        print("From server:",data.decode())#t转换为字节串
    
    sockfd.close()
    
    
    
    
    
    
    
    
    
    
    
    
    
    更多相关内容
  • 套接字编程大文件传输.zip,客户端.cpp,服务器.cpp
  • 主要为大家详细介绍了Python网络编程的相关资料,Python套接字编程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Socket套接字—Java套接字编程
  • 浅析 C#中的套接字编程 C#是微软随着 新推出的一门语言它作为一门新兴的语言有着 C++的强健又有着 VB等的 RAD 特性而且微软推出 C#主要的目的是为了对抗 Sun 公司的 Java 大家都知道 Java 语言的强大功能尤其在 网络...
  • 套接字编程

    2021-02-25 01:51:57
    套接字编程
  • linux套接字编程快速入门.doc Linux套接字编程平台认识等内容 希望能够帮到大家~
  • 该资源含有100道C#套接字编程的复习题+答案,非常值得初学者练习、复习、巩固知识!
  • 原始套接字编程

    2018-09-14 20:39:24
    linux原始套接字编程,利用原始套接字实现arp请求和接收源代码
  • COMS4119-SMTP-Socket:套接字编程以实现客户端使用SMTP发送电子邮件
  • Java套接字编程

    2014-03-20 22:15:43
    Java套接字编程,关于java套接字的编程文档
  • Socket套接字—Java套接字编程(上1)
  • Qt套接字编程源码

    2017-03-25 11:55:59
    Qt套接字编程源码
  • java套接字编程 本教程是Java套接字编程的简介,从一个简单的客户机-服务器示例开始,该示例演示了Java I / O的基本功能。 将向您介绍原始的java.io软件包和NIO,即Java 1.4中引入的非阻塞I / O( java.nio )API。 ...

    java套接字编程

    本教程是Java套接字编程的简介,从一个简单的客户机-服务器示例开始,该示例演示了Java I / O的基本功能。 将向您介绍原始的java.io软件包和NIO,即Java 1.4中引入的非阻塞I / O( java.nio )API。 最后,您将看到一个示例,该示例演示了在NIO.2中从Java 7向前实现的Java网络。

    套接字编程可归结为两个相互通信的系统。 通常,网络通信有两种形式:传输控制协议(TCP)和用户数据报协议(UDP)。 TCP和UDP用于不同目的,并且都有独特的约束:

    • TCP是相对简单且可靠的协议,它使客户端可以连接到服务器,并使两个系统进行通信。 在TCP中,每个实体都知道已收到其通信有效载荷。
    • UDP是一种无连接协议 ,适用于不一定需要每个数据包到达其目的地的情况,例如媒体流。

    要了解TCP和UDP之间的区别,请考虑如果您从自己喜欢的网站流式传输视频并且丢帧了会发生什么情况。 您是希望客户端放慢影片的速度来接收丢失的帧,还是希望视频继续播放? 视频流协议通常利用UDP。 因为TCP保证传送,所以它是HTTP,FTP,SMTP,POP3等的首选协议。

    在本教程中,我向您介绍Java中的套接字编程。 我提供了一系列客户机/服务器示例,这些示例演示了原始Java I / O框架中的功能,然后逐步推进使用NIO.2中引入的功能。

    老式Java套接字

    在NIO之前的实现中,Java TCP客户端套接字代码由java.net.Socket类处理。 以下代码打开与服务器的连接:

    Socket socket = new Socket( server, port );

    一旦我们的socket实例连接到服务器,我们就可以开始获取到服务器的输入和输出流。 输入流用于从服务器读取数据,而输出流用于将数据写入服务器。 我们可以执行以下方法来获取输入和输出流:

    InputStream in = socket.getInputStream();
    	OutputStream out = socket.getOutputStream();

    因为这些是普通流,所以我们将使用它们从文件中读取和写入文件,因此可以将它们转换为最适合我们用例的形式。 例如,我们可以将OutputStreamPrintStream包裹在一起,以便我们可以轻松地使用诸如println()类的方法编写文本。 再举一个例子,我们可以通过InputStreamBufferedReader包装InputStreamReader ,以便使用readLine()类的方法轻松读取文本。

    下载
    “ Java套接字编程:教程”的源代码。 由Steven Haines为JavaWorld创建。

    Java套接字客户端示例

    让我们来看一个简短的示例,该示例针对HTTP服务器执行HTTP GET。 HTTP比我们的示例所允许的更为复杂,但是我们可以编写客户端代码来处理最简单的情况:从服务器请求资源,然后服务器返回响应并关闭流。 这种情况需要执行以下步骤:

    1. 创建一个侦听端口80的Web服务器套接字。
    2. 获取服务器的PrintStream并发送GET PATH HTTP/1.0请求,其中PATH是服务器上请求的资源。 例如,如果我们要打开网站的根目录,则路径为/
    3. 获取服务器的InputStream ,将其包装为BufferedReader然后逐行读取响应。

    清单1显示了此示例的源代码。

    清单1. SimpleSocketClientExample.java

    package com.geekcap.javaworld.simplesocketclient;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.Socket;
    
    public class SimpleSocketClientExample
    {
        public static void main( String[] args )
        {
            if( args.length < 2 )
            {
                System.out.println( "Usage: SimpleSocketClientExample <server> <path>" );
                System.exit( 0 );
            }
            String server = args[ 0 ];
            String path = args[ 1 ];
    
            System.out.println( "Loading contents of URL: " + server );
    
            try
            {
                // Connect to the server
                Socket socket = new Socket( server, 80 );
    
                // Create input and output streams to read from and write to the server
                PrintStream out = new PrintStream( socket.getOutputStream() );
                BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
    
                // Follow the HTTP protocol of GET <path> HTTP/1.0 followed by an empty line
                out.println( "GET " + path + " HTTP/1.0" );
                out.println();
    
                // Read data from the server until we finish reading the document
                String line = in.readLine();
                while( line != null )
                {
                    System.out.println( line );
                    line = in.readLine();
                }
    
                // Close our streams
                in.close();
                out.close();
                socket.close();
            }
            catch( Exception e )
            {
                e.printStackTrace();
            }
        }
    }

    清单1接受两个命令行参数:要连接的服务器(假设我们正在端口80上连接服务器)和要检索的资源。 它创建一个指向服务器的Socket ,并显式指定端口80 。 然后执行以下命令:

    GET PATH HTTP/1.0

    例如:

    GET / HTTP/1.0

    刚才发生了什么?

    当您从网络服务器(例如www.google.com检索网页时,HTTP客户端会使用DNS服务器查找服务器的地址:首先从顶级域服务器询问com域的权威域,名称服务器用于www.google.com 。 然后,它要求该域名服务器提供www.google.com的IP地址。 接下来,它在端口80上打开该服务器的套接字。(或者,如果要定义其他端口,则可以通过在端口号之前添加冒号来实现,例如:8080 。)最后,HTTP客户端执行指定的HTTP方法,例如GETPOSTPUTDELETEHEADOPTI/ONS 。 每种方法都有自己的语法。 如上面的代码片段所示, GET方法需要一个路径,后跟HTTP/version number和空行。 如果要添加HTTP标头,可以在输入新行之前完成。

    在清单1中,我们检索了OutputStream并将其包装在PrintStream以便我们可以更轻松地执行基于文本的命令。 我们的代码获得了InputStream ,将其包装在InputStreamReader ,然后将其转换为Reader ,然后将其包装在BufferedReader 。 我们使用PrintStream执行GET方法,然后使用BufferedReader逐行读取响应,直到收到null响应,表明套接字已关闭。

    现在执行此类,并向其传递以下参数:

    java com.geekcap.javaworld.simplesocketclient.SimpleSocketClientExample www.javaworld.com /

    您应该看到类似于以下内容的输出:

    Loading contents of URL: www.javaworld.com
    HTTP/1.1 200 OK
    Date: Sun, 21 Sep 2014 22:20:13 GMT
    Server: Apache
    X-Gas_TTL: 10
    Cache-Control: max-age=10
    X-GasHost: gas2.usw
    X-Cooking-With: Gasoline-Local
    X-Gasoline-Age: 8
    Content-Length: 168
    Last-Modified: Tue, 24 Jan 2012 00:09:09 GMT
    Etag: "60001b-a8-4b73af4bf3340"
    Content-Type: text/html
    Vary: Accept-Encoding
    Connection: close
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="utf-8" />
    	<title>Gasoline Test Page</title>
    </head>
    <body>
    <br><br>
    <center>Success</center>
    </body>
    </html>

    此输出显示JavaWorld网站上的测试页。 它回复说它使用HTTP版本1.1,响应为200 OK

    Java套接字服务器示例

    我们已经介绍了客户端,幸运的是服务器端的通信方面也很容易。 从简单的角度看,该过程如下:

    1. 创建一个ServerSocket ,指定要监听的端口。
    2. 调用ServerSocketaccept()方法在配置的端口上侦听客户端连接。
    3. 当客户端连接到服务器时, accept()方法将返回一个Socket ,服务器可以通过该Socket与客户端进行通信。 这是我们用于客户端的Socket类,因此过程是相同的:获取要从客户端读取的InputStream和向客户端写入的OutputStream
    4. 如果服务器需要可伸缩性,则需要将Socket传递给另一个线程进行处理,以便服务器可以继续侦听其他连接。
    5. 再次调用ServerSocketaccept()方法以侦听另一个连接。

    正如您很快将看到的,NIO对这种情况的处理将有所不同。 不过,到目前为止,我们可以通过向其传递一个端口来直接创建ServerSocket进行侦听(在下一节中,更多关于ServerSocketFactory的信息):

    ServerSocket serverSocket = new ServerSocket( port );

    现在我们可以通过accept()方法接受传入的连接:

    Socket socket = serverSocket.accept();
    	// Handle the connection ...

    使用Java套接字的多线程编程

    下面的清单2将到目前为止的所有服务器代码放到一个更健壮的示例中,该示例使用线程来处理多个请求。 所示服务器是回显服务器 ,表示它回显收到的任何消息。

    尽管清单2中的示例并不复杂,但是它确实可以预期NIO的下一部分中将要介绍的一些内容。 要特别注意我们为了构建可以处理多个同时请求的服务器而必须编写的线程代码量。

    清单2. SimpleSocketServer.java

    package com.geekcap.javaworld.simplesocketclient;
    
    import java.io.BufferedReader;
    import java.io.I/OException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class SimpleSocketServer extends Thread
    {
        private ServerSocket serverSocket;
        private int port;
        private boolean running = false;
    
        public SimpleSocketServer( int port )
        {
            this.port = port;
        }
    
        public void startServer()
        {
            try
            {
                serverSocket = new ServerSocket( port );
                this.start();
            }
            catch (I/OException e)
            {
                e.printStackTrace();
            }
        }
    
        public void stopServer()
        {
            running = false;
            this.interrupt();
        }
    
        @Override
        public void run()
        {
            running = true;
            while( running )
            {
                try
                {
                    System.out.println( "Listening for a connection" );
    
                    // Call accept() to receive the next connection
                    Socket socket = serverSocket.accept();
    
                    // Pass the socket to the RequestHandler thread for processing
                    RequestHandler requestHandler = new RequestHandler( socket );
                    requestHandler.start();
                }
                catch (I/OException e)
                {
                    e.printStackTrace();
                }
            }
        }
    
        public static void main( String[] args )
        {
            if( args.length == 0 )
            {
                System.out.println( "Usage: SimpleSocketServer <port>" );
                System.exit( 0 );
            }
            int port = Integer.parseInt( args[ 0 ] );
            System.out.println( "Start server on port: " + port );
    
            SimpleSocketServer server = new SimpleSocketServer( port );
            server.startServer();
    
            // Automatically shutdown in 1 minute
            try
            {
                Thread.sleep( 60000 );
            }
            catch( Exception e )
            {
                e.printStackTrace();
            }
    
            server.stopServer();
        }
    }
    
    class RequestHandler extends Thread
    {
        private Socket socket;
        RequestHandler( Socket socket )
        {
            this.socket = socket;
        }
    
        @Override
        public void run()
        {
            try
            {
                System.out.println( "Received a connection" );
    
                // Get input and output streams
                BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
                PrintWriter out = new PrintWriter( socket.getOutputStream() );
    
                // Write out our header to the client
                out.println( "Echo Server 1.0" );
                out.flush();
    
                // Echo lines back to the client until the client closes the connection or we receive an empty line
                String line = in.readLine();
                while( line != null && line.length() > 0 )
                {
                    out.println( "Echo: " + line );
                    out.flush();
                    line = in.readLine();
                }
    
                // Close our connection
                in.close();
                out.close();
                socket.close();
    
                System.out.println( "Connection closed" );
            }
            catch( Exception e )
            {
                e.printStackTrace();
            }
        }
    }

    翻译自: https://www.infoworld.com/article/2853780/socket-programming-for-scalable-systems.html

    java套接字编程

    展开全文
  • APUE UINX环境高级编程 网络编程 socket套接字 字节序 字节序转换函数 ...基本TCP套接字编程 概要 socket函数 bind函数 listen函数 accept函数 connect函数 通信函数 read 和 write 关闭通信close 和 shutdown

    准备知识

    字节序

    假如有一个16位的整数,它占了2字节,有两种存储方法
    小端字节序:将低序字节存储在起始地址
    大端字节序:将高序字节存储在起始地址

    这两种方法都有系统在用,所以网络通信需要转化字节序

    我们把某个系统上使用的字节序称为 主机字节序
    把网络协议使用的字节序称为 网络字节序

    网络字节序都是采用大端字节序
    而主机字节序却没有标准而言

    字节序转换函数

    原型

    uint16_t htons(uint16_t  h16bitval);  // 主机转网络,短型
    uint32_t htonl(uint32_t  h32bitval); // 主机转网络,长型
    uint16_t ntohs(uint16_t  n16bitval);// 网络转主机,短型
    uint32_t ntohl(uint32_t  n32bitval);// 网络转主机,长型
    

    h表示主机,n表示网络,s表示short,l 表示long

    字节操纵函数

    字节操纵函数有两组
    一是

    void bzero(void *dest, size_t nbytes);
    void bcopy(const void *src, void *dest, size_t nbytes);
    int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);
    

    其中bzero是将目标字节串中指定大小的字节数置为0,参数dest是指向首地址的指针,参数nbytes是需要设置的字节数。

    bcopy函数用来复制内存的
    参数src 为源内存块指针,dest 为目标内存块指针,n 为要复制的内存的前 n 个字节长度

    bcmp的功能是比较ptr1和ptr2的前n个字节是否相等
    如果ptr1=ptr2或n=0则返回零,否则返回非零值。bcmp不检查NULL。

    二是

    void *memset(void *dest, int c, size_t len);
    void *memcpy(void *dest, const void *src,size_t nbytes);
    int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);
    

    memset是将目标字节串的指定数目(len)置为值 c
    memcpy,和bcopy作用和用法一致,注意参数顺序不一样
    memcmp 功能和bcmp一致

    地址转换函数

    我们在表示ipv4的IP地址时习惯使用点分十进制来表示,用的是字符串的形式
    但是在实际使用中需要使用IP地址的二进制形式

    所以需要一个函数来进行互相转换

    原型

    int inet_aton(const char *strptr, struct in_addr *addrptr)
    /*将字符串地址转化为二进制地址 成功返回1,否则返回0*/
    
    char *inet_ntoa(struct in_addr inaddr);
    /*将二进制地址转换为字符串地址, 返回一个点分十进制表示的字符串地址 */
    

    其中的struct in_addr是地址结构内的成员,接下来会讲解
    但是以上两个函数,只支持ipv4的地址

    接下来两函数,支持ipv4和ipv6

    int inet_pton(int family, const char *strptr, void *addrptr)
    /*将字符串地址转化为二进制地址 成功返回1,输入无效返回0,错误返回-1*/
    
    char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);
    /*将二进制地址转换为字符串地址, 返回一个点分十进制表示的字符串地址 */
    

    两个函数的参数family 可以是 AF_INET(表示IPv4),AF_INET6 (表示IPV6)

    第一个函数的参数strptr是需要转换的字符串的指针,addrptr用于存放结果

    第二个函数的addrptr是需要转换的二进制,strptr是存放结果字符串的指针,len是str的长度,太小会报错

    地址结构

    很多套接字函数需要一个指向套接字地址结构的指针作为参数,每个协议族都有自己的地址结构体

    但是最终都会强制转换为通用的socket地址结构来传参给函数

    通用套接字 sockaddr 类型定义:

    typedef unsigned short int sa_family_t;
    struct sockaddr { 
     sa_family_t sa_family; /* 2 bytes address family, AF_xxx */
     char sa_data[14]; /* 14 bytes of protocol address */
    }
    

    ipv4对应的是sockaddr_in类型定义:

    注意这里的sin_addr 是一个结构体,

    typedef unsigned short sa_family_t;
    typedef uint16_t in_port_t;
    struct in_addr {
     uint32_t s_addr; 
    };
    struct sockaddr_in {
     uint8_t sin_len;
     sa_family_t sin_family; /* 2 bytes address family, AF_xxx such as AF_INET */
     in_port_t sin_port; /* 2 bytes port*/
     struct in_addr sin_addr; /* 4 bytes IPv4 address*/
     /* Pad to size of `struct sockaddr'. */
    unsigned char sin_zero[8]; /* 8 bytes unused padding data, always set be zero */
    };
    

    ipv6对应的sockaddr_in6类型定义:

    typedef unsigned short sa_family_t;
    typedef uint16_t in_port_t;
    struct in6_addr
    {
     union
     {
     uint8_t __u6_addr8[16];
     uint16_t __u6_addr16[8];
     uint32_t __u6_addr32[4];
     } __in6_u;
    }
    struct sockaddr_in6 {
     sa_family_t sin6_family; /*2B*/
     in_port_t sin6_port; /*2B*/
     uint32_t sin6_flowinfo; /*4B*/
     struct in6_addr sin6_addr; /*16B*/
     uint32_t sin6_scope_id; /*4B*/
    };
    

    Unix域对应的sockaddr_un类型定义:

    #define UNIX_PATH_MAX 108
    struct sockaddr_un {
     sa_family_t sun_family; 
     char sun_path[UNIX_PATH_MAX]; 
    };
    

    在使用地址结构前,我们一般先将所有字节都置0,使用czero或memset函数,然后在赋值

    接下来我们将在使用时再讨论

    基本TCP套接字编程

    概要

    基本流程
    在这里插入图片描述

    socket函数

    socket函数的作用,就相当于我们要读文件时要先open
    socket会创建一个socket描述符(和文件描述符一样),后续将使用它进行连接等操作

    对于服务器来说,这个描述符是用于监听连接的,实际连接传输的描述符在accept处介绍

    原型

    int socket(int family, int type, int prttocol);
    /* 成功返回描述符,出错返回-1
    

    注意以下出参数并不是任意的搭配都是有效的
    一般SOCK_STREAM是TCP/SCTP
    SOCK_DGRAM是UDP
    两个都可以和AF_INET、AF_INET6搭配

    参数family,表示协议族,取值有

    取值含义
    AF_INETIPV4
    AF_INET6IPV6
    AF_LOCALUNIX域协议
    AF_ROUTE路由套接字
    AF_KEY秘钥套接字

    参数type指明套接字类型

    取值含义
    SOCK_STREAM字节流套接字
    SOCK_DGRAM数据套接字
    SOCK_SEQPACKET有序分组套接字
    SOCK_RAW原始套接字

    参数protocol是某个协议类型常值,通常设为0,让其默认选择。

    应用实例

    进行tcp连接时

    socket(AF_INET,SOCK_STREAM,0);
    

    bind函数

    将一个本地协议地址赋予一个套接字,就是绑定ip地址和端口的
    通常服务器在启动的时候都会绑定一个众所周知的地址(如
    ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,由系统自动分配一个端口号和自身的ip地址组合。

    通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

    当然客户端也可以在调用connect()之前bind一个地址和端口,这样就能使用特定的IP和端口来连服务器了
    原型

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    /* 成功返回0,失败返回-1 */
    

    参数sockfd:是socket描述字,bind()函数就是将给这个描述字绑定地址和端口
    参数addrlen:对应的是地址的长度
    参数addr:地址结构指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,但最终都会强制转换后赋值给sockaddr这种类型的指针传给内核

    应用实例

    struct socket_in   sockaddr_in;
    int port = 12345;
    
    memset(&sockaddr_in,0,sizeof(sockaddr_in));
    
    sockaddr_in.sin_family = AF_INET;
    sockaddr_in.sin_port = htons(port);
    sockaddr_in.sin_addr.s_addr = htonl(INADDR_ANY);   //INADDR_ANY 代表可以运行任何ip连接
    
    bind(socket_fd, (struct sockaddr *)&sockaddr_in,sizeof(sockaddr_in));
    
    

    listen函数

    socket创建的描述符,默认是一个主动类型的(就是主动调用connect去连接别人的,是一个客户端),调用listen后转为主动的,并开始监听socket描述符,等待用户连接

    原型

    int listen(int sockfd, int backlog);
    /* 成功返回0,失败返回-1 */
    

    参数sockfd,是socket描述符
    参数backlog 是最大连接个数

    最大连接数说明

    TCP建立连接是要进行三次握手,但是完成三次握手后,服务器需要维护这种状态:
      半连接状态为:服务器处于Listen状态时收到客户端SYN报文时放入半连接队列中,即SYN queue(服务器端口状态为:SYN_RCVD)。
      全连接状态为:TCP的连接状态从服务器(SYN+ACK)响应客户端后,到客户端的ACK报文到达服务器之前,则一直保留在半连接状态中;
      
    在Linux内核2.2之前,backlog大小包括半连接状态和全连接状态两种队列大小,

    在Linux内核2.2之后,分离为两个backlog来分别限制半连接(SYN_RCVD状态)队列大小和全连接(ESTABLISHED状态)队列大小

    SYN queue 队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,默认为2048。

    Accept queue 队列长度由 /proc/sys/net/core/somaxconn 和使用listen函数时传入的参数,二者取最小值。默认为
    128

    accept函数

    服务器在调用accept函数后,会阻塞监听socket,等待客户端连接,并返回一个全新的描述符fd,代表与客户端的tcp连接

    原型

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    /* 成功返回一个用于连接的描述符,失败返回-1 */
    
    

    参数sockfd: 服务器开始调用socket()函数生成的,称为监听socket描述字;
    参数*addr: 用于返回客户端的协议地址,这个地址里包含有客户端的IP和端口信息等,结构体与bind中的一致
    参数addrlen: 返回客户端协议地址的长度

    accept函数的返回值是由内核自动生成的一个全新的描述字(fd),代表与返回客户的TCP连接。如果想发送数据给该客户端,则我们可以调用write()等函数往该fd里写内容即可;而如果想从该客户端读内容则调用read()等函数从该fd里读数据即可。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个新的socket描述字,当服务器完成了对某个客户的服务,就应当把该客户端相应的的socket描述字关闭。

    connect函数

    tcp客户端在创建socket后,使用connect来连接服务器
    这两个文件描述符(客户端connect的fd和服务器端accept返回的fd)就可以实现客户端和服务器端的相互通信。

    原型

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    /* 成功返回0,失败返回-1 */
    

    sockfd: 客户端的socket()创建的描述字
    addr: 要连接的服务器的socket地址结构,这里面包含有服务器的IP地址和端口等信息,和bind的一致
    addrlen: socket地址的长度

    实例

    struct socket_in   sockaddr_in;
    int port = 12345;
    char *ip =192.168.1.1memset(&sockaddr_in,0,sizeof(sockaddr_in));
    
    sockaddr_in.sin_family = AF_INET;
    sockaddr_in.sin_port = htons(port);
    inet_aton(ip, &sockaddr_in,sin_addr);
    
    connect(socket_fd, (struct sockaddr *)sockaddr_in, sizeof(sockaddr_in));
    

    通信函数 read 和 write

    以上的函数已足够服务器和客户端建立tcp连接
    接下来我们介绍用于通信的函数

     ssize_t read(int fd, void *buf, size_t count);
     ssize_t write(int fd, const void *buf, size_t count);
     ssize_t send(int sockfd, const void *buf, size_t len, int flags);
     ssize_t recv(int sockfd, void *buf, size_t len, int flags);
     ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr,
    socklen_t addrlen);
     ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t
    *addrlen);
     ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
     ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    
    

    其中read 和 write用法与文件io中的一致,用法如下
    UNIX环境编程(c语言)–文件I/O-文件共享

    其他函数也不再一一介绍,用法大同小异,详细用法可以man手册查看

    关闭通信close 和 shutdown

    使用close关闭通信,就和文件io中的用法一样,详情看上面那个链接文件io的文章

    如果对socket fd调用close()则会触发该TCP连接断开的四路握手,有些时候我们需要数据发送出去并到达对方之后才能关闭
    socket套接字,则可以调用shutdown()函数来半关闭套接字:

    int shutdown(int sockfd, int how);
    

    如果how的值为 SHUT_RD 则该套接字不可再读入数据了; 如果how的值为 SHUT_WR 则该套接字不可再发送数据了; 如
    果how的值为 SHUT_RDWR 则该套接字既不可以读,也不可以写数据了

    展开全文
  • 这个文档是一个指南,而不是参考书。如果你刚开始 socket 编程并想找一本入门书,那么你是我的读者。但这不是一本完全的socket 编程书。
  • 完成了Linux下简单的TCP套接字编程,是一个完整的TCP客户端/服务器实例
  • 计算机网络实验报告套接字编程
  • web server 套接字编程

    2017-12-13 23:13:15
    用java语言编写的web server 套接字编程,深入理解http协议及web服务器的实验原理
  • MFC套接字编程

    2015-10-26 08:31:41
    MFC套接字编程 MFC资源开发专用网络编程相关必备资源 新手适用
  • Linux下的TCP套接字编程

    千次阅读 2021-12-23 19:22:01
    创建socket套接字 //函数原型 #include<sys/types.h> #include <sys/socket.h> int socket(int family, int type, int protocol); /*返回值 成功:非负描述字,即非负整数值,称为套接字。同文件描述符...

    客户端

    基本流程

    创建socket套接字

    //函数原型
    #include<sys/types.h>
    #include <sys/socket.h>
    int socket(int family, int type, int protocol);
    /*返回值
    成功:非负描述字,即非负整数值,称为套接字。同文件描述符类似
    出错:-1*/
    /*参数
    family:协议族,一般都是AF_INET(ipv4协议)或者PF_INET6(ipv6协议)
    type:套接字通信类型,一般是SOCK_STREAM(tcp)或者SOCK_DGRAM(udp)
    protocol:制定某个协议的特定类型,一般设置为0
    */
    

    设置与服务器ip和服务器端口相关的数据结构

    #include <netinet/in.h>
    struct in_addr {
       in_addr_t 		s_addr;
    };
    struct sockaddr_in {
       uint8_t          	sin_len;//地址结构长度
       sa_family_t      	sin_family; //协议族,与socket函数第一个参数相同
       in_port_t        	sin_port; //端口号
       struct in_addr   	sin_addr; //IP地址
       char             	sin_zero[8]; //填充字段
    }; 
    sockaddr_in serverAddress;
    //使用前要将其清零
    memset(&serverAddress, 0, sizeof(sockaddr_in);
    //端口赋值
    serverAddress.sin_port = htons(4000);//使用htons()函数是因为主机字节序列(小端)和网络字节序列(大端)不同
    //服务器ip地址赋值
    #include <arpa/inet.h>
    int inet_aton(const char* strptr, struct in_addr *addrptr);//将strptr指向的字符串,转换成32位的网络字节序二进制值,并存储在addrptr指向的结构体中
    in_addr_t inet_addr(const char* strptr); //将strptr指向的字符串,转换成32位的网络字节序二进制值,将其作为返回值返回
    serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
    int inet_pton(int family, const char* strptr, void *addrptr);//addrptr:转换strptr指向的字符串,将网络字节序的二进制值,存储在addrptr指向的内存
    //通常addrptr指向sockaddr_in或sockaddr_in6
    inet_pton(AF_INET, strServerIP, &serverAddress.sin_addr)
    
    

    连接服务器

    //函数原型
    #include <sys/socket.h>
    int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
    connect(nClientSocket, (sockaddr*)&ServerAddress, sizeof(ServerAddress))
    /*
    connect激发TCP的三路握手过程;仅在连接建立成功或出错时才返回
    其中错误有以下几种情况:
    如果客户没有收到SYN分节的响应(总共75秒,这之间需要可能需要重发若干次SYN),则errno被设置为ETIMEDOUT(等于110)。
    如果对客户的SYN的响应是RST,则表明该服务器主机在该端口上没有进程在等待。errno被设置成ECONNREFUSED(等于111);
    如果客户发出的SYN在中间路由器上引发一个目的地不可达ICMP错误,则如第一种情况,连续发送SYN,直到规定时间仍未收到响应,则errno被设置成EHOSTUNREACH(113)或ENETUNREACH(101)。
    如果函数connect失败,则套接字不可再用,必须关闭。不能再对此套接字再调用函数connect。
    */
    

    服务器端

    基本流程

    创建socket套接字

    同客户端

    设置与服务器ip和服务器端口相关的数据结构

    同客户端

    ServerAddress.sin_addr.s_addr = htonl(INADDR_ANY);//设置为本地ip
    

    绑定套接字和服务器ip及端口

    int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
    bind(nListenSocket, (sockaddr *)&ServerAddress, sizeof(sockaddr_in));
    //返回值:成功为0,出错为-1
    /*
    TCP服务器或客户端,都可以不调用或调用bind函数
    TCP服务器通常都要调用bind函数,绑定在一个预先设置好的端口上
    若TCP服务器不调用bind函数,当调用listen函数时,内核将自动分配一个端口
    TCP客户端通常都不要调用bind函数,当调用connect函数时,内核自动分配一个端口
    */
    

    监听

    //函数原型
    #include<sys/socket.h>
    int listen(int sockfd, int backlog);
    //返回值:成功返回0,出错返回-1
    //listen的第二个参数规定了内核应该为相应套接口排队的最大连接个数
    /*当调用完listen函数,无论服务器是否调用accept函数(从监听队列中取出一个连接)
    客户端都可以向服务器发送数据,数据将保存在已连接套接口的接收缓冲区中*/
    listen(nListenSocket, nLengthOfQueueOfListen);
    

    接受客户端连接

    //函数原型
    #include<sys/socket.h>
    int accept(int sockfd, struct sockaddr *cliaddr,  socklen_t *addrlen);
    //cliaddr:当accept函数返回时,内核将从已完成连接队列中,取出一个连接;并将该连接的客户端信息(协议族、IP、Port),保存在cliaddr指向的结构体中
    //可以将cliaddr和addrlen设置为NULL
    sockaddr_in ClientAddress;
    socklen_t LengthOfClientAddress = sizeof(sockaddr_in);
    int nConnectedSocket = ::accept(nListenSocket, (sockaddr *)&ClientAddress, &LengthOfClientAddress);
    

    其他接口

    获取本地和远端协议地址

    //函数原型
    int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
    /*参数
    sockfd:需要查询的套接字
    localaddr:该函数返回时,填充该结构
    addrlen:调用该函数之前,让*addrlen为localaddr指向的套接口地址结构大小;调用之后,为实际套接口地址结构大小
    0:成功,-1:出错*/
    
    //函数原型
    int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
    /*返回远端的地址或端口信息(服务器调用,返回客户,客户调用返回服务器)
    参数
    sockfd:需要查询的套接字
    peeraddr:该函数返回时,填充该结构
    addrlen:调用该函数之前,让*addrlen为localaddr指向的套接口地址结构大小;调用之后,为实际套接口地址结构大小
    0:成功,-1:出错*/
    

    接收数据

    #include <unistd.h>
    int read(int fd, char *buf, int len);
    /*		返回:大于0-读写字节大小;-1-出错;
    调用函数read时,有如下几种情况:
    套接字接收缓冲区接收到数据,返回接收到的字节数;
    tcp协议收到FIN数据,返回0;
    tcp协议收到RST数据,返回-1,同时errno为ECONNRESET;
    进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。*/
    
    

    发送数据

    #include <unistd.h>
    int write(int fd, char *buf, int len);
     /*                    返回:大于0-读写字节大小;-1-出错;
    
    调用函数write,有如下几种情况:
    套接字发送缓冲区有足够空间,返回发送的字节数;
    tcp协议接收到RST数据,返回-1,同时errno为ECONNRESET; ;
    进程阻塞过程中接收到信号,返回-1,同时errno为EINTR。*/
    

    一个简单的示例

    https://download.csdn.net/download/m0_37271605/71979131

    展开全文
  • Java 套接字编程Java 套接字编程Java 套接字编程Java 套接字编程Java 套接字编程Java 套接字编程
  • 第一章 理解网络编程套接字 1.1 网络编程套接字概要 1.2 基于Linux的文件操作 1.2.1 底层文件访问和文件描述符 1.2.2 打开文件 1.2.3 关闭文件 1.2.4 将数据写入文件 1.2.5 读取文件中的数据 第二章 ...
  • python的UDP套接字编程

    千次阅读 2022-03-22 18:02:34
    下面的代码用来理解UDP套接字 客户端代码 from socket import * from pip._vendor.distlib.compat import raw_input #127.0.0.1是本地回环地址,经常用来进行测试 def main(): server_address = '127.0.0.1' # ...
  • C++的TCP套接字编程的基本步骤

    千次阅读 2022-03-31 10:32:15
    3将套接字设置为监听模式等待连接请求(使用函数listen),这个套接字就是监听套接字。 4请求到来时,接受连接请求,返回一个新的对此次连接的套接字(accept)。 5用返回新的套接字和客户端进行通信,即发送或接收...
  • 基于Java的Socket套接字编程 源代码
  • 主要介绍了Python网络编程之TCP与UDP协议套接字用法,结合实例形式较为详细的分析了Python网络编程中TCP与UDP协议客户端、服务器端相关实现及使用技巧,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 270,612
精华内容 108,244
关键字:

套接字编程

友情链接: LED-Dot-Matrix-Display.zip