精华内容
下载资源
问答
  • 摘要  TCP/IP协议族是构建互联网的基石协议。...TCP能够确保数据的传送,也确保数据包以它们正确的顺序传送,是一种提供可靠连接的传送协议。由于Java语言支持基于流的通信,即是用TCP协议进行传输,所以本

    摘要

            TCP/IP协议族是构建互联网的基石协议。在互联网中,从一台计算机向另外一台计算机传送数据,数据包可以通过两种协议传输。其中一种就是传输控制协议(Transmission Control Protocol,TCP)。TCP能够确保数据的传送,也确保数据包以它们正确的顺序传送,是一种提供可靠连接的传送协议。由于Java语言支持基于流的通信,即是用TCP协议进行传输,所以本次的课程设计将基于Java语言,设计出一个可以发送TCP数据包的程序。

    关键字

    传输控制协议(TCP),Java,套接字(Socket),IP,端口(Port)

    1 引言

            在互联网的四层协议中,TCP位于IP层之上,应用层之下的传输层。不同主机的应用层之间经常需要可靠的、像管道一样的连接。而面向连接、提供可靠传输的TCP协议则正好能够满足这一需求。因此被广泛利用。

            掌握TCP数据包的发包原理和功能的实现,有利于我们能够更进一步地学习和利用更多应用层上的应用和技术,如文件传送(FTP)、远程登录(RemoteLogin)等。

            本次课程设计要求我们能够实现以下效果:

    (1) 以命令行形式运行:

    SendTCP source_IP  source_port  dest_ip dest_port

    其中,SendTCP为程序名,source_IP为源端IP地址,source_port为源端口,dest_ip 为目的IP地址,dest_port为目的端口

    (2) 其他的TCP头部参数请自行设定。

    (3) 数据字段为“Thisis my homework of network ,I am happy!”.

    (4) 成功发送后在屏幕上输出“SendOK”。

    2 总体设计  

    2.1 系统或算法框架设计

    (1) 服务端的设计框架(发送数据段方)


    (2) 客户端的设计框架(发送反馈信息方)

    2.2 功能设计

            在本次课程设计中,要求发送一段数据包,里面包含一段数据信息。同时,为了验证数据包发送成功,还需要进行验证。因此需要实现至少发送数据包和验证发送是否成功的两项功能。建立服务端发送数据段,客户端接收数据段并发送反馈信息。当它们分别运行在不同的主机上,运行程序。根据程序的运行情况,便能验证这两项功能。



            在服务端,我们首先建立对源端口的监听。当客户端成功连接到源端口时,服务端即按要求发送数据段“This is my homework of network ,I amhappy!”到目的IP、端口。客户端,新建端口的监听,当收到数据段后发送“SendOK!”反馈给服务端。通过这样的数据包传送的数据,便能实现以上两种功能,见图3。要注意的是,服务端的源IP、端口即为客户端的目的IP、端口;服务端的目的IP、端口即为客户端的源IP、端口。


    2.3 平台设计

             本次的课程设计在Java语言的平台上利用Java语言实现。为了实现在两台计算机发送数据包的功能。本次实验采用了物理机和虚拟机模拟在同一个局域网中。其中物理机采用Windows 8.1系统,IP地址为192.168.126.53,而虚拟机则采用Windows XP系统,IP地址为192.168.126.52。如图4所示。

    2.4 数据结构的设计

            本次实验采用了String类型保存字符,而端口号则采用Int类型。而由于文本I/O需要编码和解码,所以,二进制I/O的效率比文本I/O的效率更高。因此最好使用二进制I/O在服务端和客户端之间进行数据传输,以便提高效率。因此,在读入和写入分别采用了DataInputStream和DataOutStrea这两个类。

    2.5 接口设计

            根据题目要求,程序运行时必须输入4个参数:源IP、源端口、目的IP、目的端口。程序开始时会判断是否已经输入了4个参数,如果没有输入四个参数,或输入错误,输出错误提示,如图5所示。


    3. 详细设计(按照实际情况分小点,详细书写整个的设计流程以及核心源代码)

    3.1 参数读入

             不论是客户端还是服务端,根据要求,都需要读入IP和端口信息。而服务端的源IP、端口即为客户端的目的IP、端口;服务端的目的IP、端口即为客户端的源IP、端口。

    1. String sourceIP = args[0];//源IP  
    2.     int sourcePort = Integer.parseInt(args[1]);//源端口  
    3.     String destinationIP = args[2];//目的IP  
    4.     int destinationPort = Integer.parseInt(args[3]);//目的端口  
    String sourceIP = args[0];//源IP
        int sourcePort = Integer.parseInt(args[1]);//源端口
        String destinationIP = args[2];//目的IP
        int destinationPort = Integer.parseInt(args[3]);//目的端口

    3.2 建立套接字

             无论是服务端还是客户端都需要建立套接字(Socket)。建立套接字有两种方法,一种是主动发送信息的。例外一种则是被动接收信息再发出反馈(监听)。在本次课程实验中,无论是两端既需用到主动发信息又需要用到监听。

    1. //主动发送信息,发送方向为目的IP的目的端口  
    2. Socket socket = new Socket(destinationIP, destinationPort);  
    3. DataOutputStream dataOutputStream   
    4. new DataOutputStream(socket.getOutputStream());  
    5. dataOutputStream.writeUTF("Response Please!");  
    6. //监听,接收发给源IP的源端口信息。  
    7. ServerSocket serverSocket = new ServerSocket(sourcePort);  
    8.     socket = serverSocket.accept();  
    //主动发送信息,发送方向为目的IP的目的端口
    Socket socket = new Socket(destinationIP, destinationPort);
    DataOutputStream dataOutputStream 
    = new DataOutputStream(socket.getOutputStream());
    dataOutputStream.writeUTF("Response Please!");
    //监听,接收发给源IP的源端口信息。
    ServerSocket serverSocket = new ServerSocket(sourcePort);
        socket = serverSocket.accept();

    3.3 发送或接收数据

             作为本次课程实验的重点,发送和接收是否成功是本次课程设计是否成功的关键。为了保证程序能够成功运行,本次发送的数据均采用二进制数据流。

    1.     //发送信息  
    2. DataOutputStream dataOutputStream   
    3. new DataOutputStream(socket.getOutputStream());  
    4. dataOutputStream.writeUTF("Response Please!");   
    5. //接收信息  
    6. DataInputStream dataInputStream  
    7.                         = new DataInputStream(socket.getInputStream());  
    8.                 String dataSegment=dataInputStream.readUTF();  
    	//发送信息
    DataOutputStream dataOutputStream 
    = new DataOutputStream(socket.getOutputStream());
    dataOutputStream.writeUTF("Response Please!"); 
    //接收信息
    DataInputStream dataInputStream
                            = new DataInputStream(socket.getInputStream());
                    String dataSegment=dataInputStream.readUTF();

    3.4 服务端功能实现

    服务端在本次课程设计中,主要负责往目的套接字(目的IP+端口)发送数据段“Thisis my homework of network ,I am happy! ”,并接收来时目的套接字返回的数据段“SendOK!”,见图6。

    1. //记录源和目的套接字的信息  
    2. String sourceIP = args[0];  
    3. int sourcePort = Integer.parseInt(args[1]);  
    4. String destinationIP = args[2];  
    5. int destinationPort = Integer.parseInt(args[3]);  
    6.   
    7. //建立监听  
    8. ServerSocket serverSocket = new ServerSocket(sourcePort);  
    9. Socket socket = serverSocket.accept();  
    10.   
    11. //接收来自客户端的信息  
    12. DataInputStream dataInputStream  
    13.                         = new DataInputStream(socket.getInputStream());  
    14. //发送信息  
    15. String dataSegment = "This is my homework of network ,I am happy!";  
    16. DataOutputStream dataOutputStream   
    17. new DataOutputStream(socket.getOutputStream());   
    18. dataOutputStream.writeUTF(dataSegment);  
    19.                  
    20. //接收成功信息  
    21. socket = new Socket(destinationIP, destinationPort);  
    22. dataOutputStream = new DataOutputStream(socket.getOutputStream());  
    23. dataOutputStream.writeUTF("Successfully Received!");  
    24.   
    25. dataInputStream = new DataInputStream(socket.getInputStream());  
    26. dataSegment=dataInputStream.readUTF();  
    27. PrintMessage("接收到来自" + socket.getInetAddress().toString().substring(1) + ","  
    28.                         + socket.getPort() + "号端口的信息");  
    29. PrintMessage("信息内容为:" + dataSegment);  
    30.   
    31. //关闭流  
    32. dataInputStream.close();  
    33. dataOutputStream.close();  
    34. socket.close();  
    35. serverSocket.close();  
    //记录源和目的套接字的信息
    String sourceIP = args[0];
    int sourcePort = Integer.parseInt(args[1]);
    String destinationIP = args[2];
    int destinationPort = Integer.parseInt(args[3]);
    
    //建立监听
    ServerSocket serverSocket = new ServerSocket(sourcePort);
    Socket socket = serverSocket.accept();
    
    //接收来自客户端的信息
    DataInputStream dataInputStream
                            = new DataInputStream(socket.getInputStream());
    //发送信息
    String dataSegment = "This is my homework of network ,I am happy!";
    DataOutputStream dataOutputStream 
    = new DataOutputStream(socket.getOutputStream()); 
    dataOutputStream.writeUTF(dataSegment);
                   
    //接收成功信息
    socket = new Socket(destinationIP, destinationPort);
    dataOutputStream = new DataOutputStream(socket.getOutputStream());
    dataOutputStream.writeUTF("Successfully Received!");
    
    dataInputStream = new DataInputStream(socket.getInputStream());
    dataSegment=dataInputStream.readUTF();
    PrintMessage("接收到来自" + socket.getInetAddress().toString().substring(1) + ","
                            + socket.getPort() + "号端口的信息");
    PrintMessage("信息内容为:" + dataSegment);
    
    //关闭流
    dataInputStream.close();
    dataOutputStream.close();
    socket.close();
    serverSocket.close();

    3.5 客户端功能实现

             客户端在本次课程设计中,主要负责的是接收来自服务端的信息,并发出反馈信息“Send OK!”,见图7。


    1.     //尝试连接  
    2.         Socket socket = new Socket(destinationIP, destinationPort);  
    3.         DataOutputStream dataOutputStream   
    4. new DataOutputStream(socket.getOutputStream());  
    5.         dataOutputStream.writeUTF("Response Please!");  
    6.   
    7.    //获得回应  
    8. DataInputStream dataInputStream  
    9. new DataInputStream(socket.getInputStream());  
    10. String dataSegment = dataInputStream.readUTF();  
    11. PrintMessage("接收到来自" + socket.getInetAddress().toString().substring(1) + ","  
    12.                         + socket.getPort() + "号端口的信息");  
    13.         PrintMessage("信息内容为:" + dataSegment);  
    14.   
    15. //回复  
    16. ServerSocket serverSocket = new ServerSocket(sourcePort);  
    17. socket = serverSocket.accept();  
    18. dataOutputStream = new DataOutputStream(socket.getOutputStream());  
    19. dataOutputStream.writeUTF("Send OK!");  
    	//尝试连接
       		Socket socket = new Socket(destinationIP, destinationPort);
            DataOutputStream dataOutputStream 
    = new DataOutputStream(socket.getOutputStream());
            dataOutputStream.writeUTF("Response Please!");
    
       //获得回应
    DataInputStream dataInputStream
    = new DataInputStream(socket.getInputStream());
    String dataSegment = dataInputStream.readUTF();
    PrintMessage("接收到来自" + socket.getInetAddress().toString().substring(1) + ","
                            + socket.getPort() + "号端口的信息");
            PrintMessage("信息内容为:" + dataSegment);
    
    //回复
    ServerSocket serverSocket = new ServerSocket(sourcePort);
    socket = serverSocket.accept();
    dataOutputStream = new DataOutputStream(socket.getOutputStream());
    dataOutputStream.writeUTF("Send OK!");
    

    4 总结

    4.2 存在的问题

    (1) 命令行界面不够美观且操作性不够强

    (2) 每次都输入4个参数太麻烦了

    4.3 改进的方法

    (1) 改用图形界面,并美化界面。但可能速度上不够现在的快。

    (2) 仿照命令提示符(cmd),可以缺省输入。

    【参考文献】

    [1]Y.Daniel Liang.Java语言程序设计(基础篇)[M].李娜,译.北京:机械工业出版社,2011:527-535

    [2]Y.Daniel Liang.Java语言程序设计(进阶篇)[M].李娜,译.北京:机械工业出版社,2011:258-264

    [3]谢希仁.计算机网络简明教程(第二版)[M].北京:电子工业出版社,2013:123-143







    展开全文
  • Wireshark捕获分析TCP数据包三次握手

    千次阅读 2020-03-21 17:59:24
    1、操作步骤 (1)打开wireshark,开始捕获界面 (2)打开一个网址(如:csdn) (3)对捕获的数据包进行分析 ... 客户端发送一个 TCP,标志位为 SYN,序列号为0,表示:客户端请求建立连接。 ...

     微信公众号: 

    1、操作步骤

    (1)打开wireshark,开始捕获界面

    (2)打开一个网址(如:csdn)

    (3)对捕获的数据包进行分析

    第一个包的作用是第一握手,发送连接请求;第二个包的作用是第二次握手,连接接受;第三个包的作用是第三次握手,对连接接受的确认。

    2、分析三次握手过程

    (1)第一次握手

      客户端发送一个 TCP,标志位为 SYN,序列号为0,表示:客户端请求建立连接。

    (2)第二次握手

      序号说明的是自己发送的数据的编号。 由于确认包是服务器发给客户端的一个数据包,对服务器来讲,这是它的第一个数据包,因此序号 seq=0。确认号是告诉对方,下一个应该发送的数据字节的编号。由于对方(客户端)上一次(第二次握手) 发来 seq 的序号字段是0,下一个应该发送的就应该是0+1=1,因此服务器发回的确认包中的确认号是1(ACK=0+1=1)。

    (3) 第三次握手

      客户端再次发送确认包(ACK) SYN 标志位为0,ACK 标志位为 ACK 有效.序号说明的是自己发送的数据的编号。由于客户端第一次握手的数据字段已成功发送1个字节,因此数据字段序号 seq 从0变为1。确认号是告诉对方,下一个应该发送的数据字节的编号。由于对方(服务器)上一次(第二次握手) 发来 seq 的序号字段是0,下一个应该发送的就应该是0+1=1,放在确定字段中发
    送给对方(ACK=0+1=1)。

    另外要注意TCP 不可以使用两次握手建立连接。因为两次握手无法处理下面出现的情况:一个已失效的连接请求在超时后到达接收端,接收端收到请求,自然会接受请求,于是等待对方发送数据,可实际对方没有数据要发送,因此不会发送数据,接收方只能空等。于是该连接就这样在无数据传输的情况下白白浪费很多资源。

    展开全文
  • 1.以命令行形式运行:SendTCP source_ip source_port dest_ip dest_port; 2.头部参数自行设定,数据字段为“This is my homework of network of network,I am happy!”; 3.成功发送后在屏幕上输出“send OK”。 ...

    任务要求:

    1.以命令行形式运行:SendTCP source_ip source_port dest_ip dest_port;
    2.头部参数自行设定,数据字段为“This is my homework of network of network,I am happy!”;
    3.成功发送后在屏幕上输出“send OK”。

    需求分析

    本系统要求使用C语言作为基本开发语言,并且开发工具为绿色软件,程序运行不需要安装和避免写系统和注册表。需要完成的需求如下:

    • 1.本程序需完成发送一个TCP数据包给目的主机,应用层将需要传送的信息传送给
      TCP层,TCP传输实体根据程序运行时输入的源IP地址、源端口号、目的IP地址、目的端口号加上TCP报头,形成TCP数据包,在TCP数据包上增加IP头部,形成IP包。
    • 2.运行程序时输入:SendTCP source_ip source_port dest_ip dest_port,然后根据提示输入要发送的数据,回车即可。
    • 3.程序的输出:Send OK!
    • 4.测试数据 SendTCP 172.27.91.240 200 172.27.91.123 100
      ,其中源IP地址、源端口号、目的IP地址、目的端口号可以任意指定。

    系统设计

    系统总体架构

    本系统的目标是发送一个TCP数据包,可以利用原始套接字来完成这个工作。整个系统由初始化原始套接字、准备与发送TCP数据包、关闭释放套接字这三个功能模块组成,在准备与发送TCP数据包功能模块里又分构造IP首部、TCP首部、TCP伪首部、填充数据包和发送数据包三个部分,由它们三个部分依次执行完成准备和发送模块功能。
    三个功能模块彼此依赖,必须都实现其功能并按一定次序运行,系统才能成功实现需求,系统总体架构图如下图所示:
    在这里插入图片描述

    功能模块

    各功能模块的关系和实现顺序如下图所示:
    在这里插入图片描述

    初始化原始套接字模块

    首先windows 初始化socket网络库,指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节,应用程序必须在初始化socket网络库之后才能调用进一步的Windows Sockets API函数。接着创建一个能够进行网络通信的套接字, 接口的类型为原始套接字,此套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,源主机所在网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给目的主机的Socket中,使这段信息能传送到其他程序中。以上为此模块功能。

    准备和发送模块

    首先为构造IP首部、TCP伪首部、TCP首部部分,在此部分要设计IP首部、TCP伪首部、TCP首部的结构体类型,分别创建对应的结构体类型的对象,并根据实际情况为其各自成员变量赋值,完成IP首部、TCP伪首部、TCP首部的填充。
    接着是填充数据包部分,在此部分要将包含TCP传送数据和首部的IP报文按IP首部、TCP首部、TCP数据的顺序填充到套接字的发送缓存区,为数据包的发送做好准备。
    最后是通过指定函数将数据包发送出去,成功发送即实现了准备与发送模块的功能。

    关闭和释放原始套接字模块

    关闭套接口,释放套接描述字,并解除与Socket库的绑定并且释放socket库所占的系统资源,以上为此模块功能。
    以上即为三个模块实现功能的解释。

    系统实现

    主要数据结构

    主要有IP首部、TCP首部以及TCP伪首部的数据结构,结构体创建的依据是各报文段首部格式,将各个字段作为成员变量,按照每个字段所占位数指定该成员变量的数据类型。
    宏定义将usigned char、usigned short、usigned long类型命名为UCHAR、USHORT、ULONG,UCHAR、USHORT、ULONG在编写本系统的机器中各占1字节、2字节、4字节,即8位、16位、32位。如有字段占8位,则将其字段对应成员变量设置为UCHAR类型,不足8位或超出8位但不是8的倍数的字段则几个字段合并,使其大于8位并能被8整除,以便指定数据类型。
    IP首部:固定长度(20字节)+可选字段;
    TCP伪首部:固定长度12字节;
    TCP首部:固定长度(20字节)+选项;

    初始化原始套接字模块实现

    socket 即是套接字, 是网络通信的基本操作单元, 可以看做是不同主机之间进程进行双向通信的端点, 即通信双方的一种约定, 可用socket的相关函数来完成通信过程,网络通信双方之间的纽带, 应用程序在网络上发送, 接受的信息都通过socket实现,socket是操作系统的资源。本系统使用raw socket (原始套接字) ,提供对网络下层通信协议(如IP协议)的直接访问。
    Windows socket 网络编程总体思路
    1、初始化 Windows socket
    2、创建socket
    3、将socket与地址结构绑定
    4、发送/接收数据
    5、释放socket
    6、终止Windows socket

    准备与发送模块实现

    构造数据结构中需要由用户设定的值有源IP地址、源端口号、目的IP地址和目的端口号,由主函数中argv[]数组将其传递到内存,再使用进行赋值。使用if语句判断是否输入符合要求,符合要求才能开始此模块。
    (1) 构造TCP 伪首部:
    TCP前需要加上一个伪首部,这个首部只用来计算校验和,并不真正地发送给另外一端。注意16位TCP报文长度字段,值为TCP首部和TCP数据总字节数相加,并使用htons()函数将主机的无符号短整形数转换成网络字节顺序,简单地说,使用htons()函数将该字段值的高低位互换。要大于8位才需要转换,小于8位不需理会。
    (2)构造TCP首部并计算检验和:
    根据实际情况为其赋值,注意16位的目的端口号字段,使用atoi()函数把输入字符串转换成整型数,函数会扫描参数字符串,跳过前面的空白字符(例如空格,tab缩进)等,直到遇上数字或正负符号才开始做转换,而在遇到非数字或字符串结束符(’\0’)才结束转换,并将结果返回。再使用htons()函数将主机的无符号短整形数转换成网络字节顺序。把TCP首部的校验和字段设置为0,将TCP伪首部和TCP报文通过memset()函数和memcpy()函数填充至检验和缓冲区,memset()函数将检验和缓冲区初始化、memcpy()函数将TCP伪首部和TCP报文拷贝至检验和缓冲区。最后通过自定义的checksum()函数完成计算检验和,并将其重新赋值给检验和字段。
    checksum()自定义函数实现原理:使用二进制反码和算法,缓冲区buffer[]类型是usigned short,每两个字节一个数组项,刚好是16位,通过sizeof()算出发送数据的字节数,作为累加的判断条件,如果没有整除(即size还有余下的不足16位的部分),则加上余下的部分,此时的cksum就是相加后的结果,这个结果往往超出了16位,因为校验和是16位的,所以要将高16位和计算得到的cksum再相加,第一步相加时很可能会产生进位,因此要再次把进位移到低16位进行相加。最后结果取反即为校验和。
    (3)构造IP首部: 
    同前面TCP首部构造方法一样,故不再做过多累述,只是源、目的IP地址字段需要使用inet_addr() 函数将点分十进制的IPv4地址转换成网络字节序列的长整型,使用将高位和地位交换。IP首部的检验和只是依靠IP首部计算出来的,通过自定义的checksum()函数完成计算检验和,并将其重新赋值给检验和字段。
    (4)填充数据包:
    填充数据包就是将包含TCP数据包的IP包填充至发送缓冲区,是通过memset()函数和memcpy()函数实现,memset()函数将发送缓存区全部初始化、memcpy()函数将包含TCP数据包的IP包按照规定顺序拷贝至检验和缓冲区。
    (5)发送数据包:
    填充好数据包后初始化发送数据报的目的地址,根据在cmd运行时输入的目的IP地址和目的端口号构造sockaddr_in结构体dest,表示目的地址,sockaddr_in结构体如下所示:

    struct sockaddr_in {
    	short	sin_family;
    	u_short	sin_port;
    	struct in_addr	sin_addr;
    	char	sin_zero[8];
    };
    

    其中sin_addr存储IP地址,使用in_addr这个数据结构。
    完成一切准备工作后使用sendto()函数发送数据包,sendto() 用来将数据由指定的socket 传给对方主机. 参数s 为已创建的socket套接字,参数msg 指向发送的数据内容, 参数flags一般设0,参数to 用来指定欲传送的网络地址,即dest。 参数tolen 为sockaddr_in结构体dest长度。如果发送成功即输出sendOK!不需要管接收方是否收到报文。

    关闭模块实现

    关闭模块非常简单,只有一个步骤,简单但必须实现,实现通过两个函数实现,closesocket()函数关闭套接口,释放套接描述字sock,以后对sock的访问均以WSAENOTSOCK错误返回,WSACleanup()解除与Socket库的绑定并且释放socket库所占的系统资源。

    系统测试(常见错误)

    系统测试发生了较多问题,具体内容如下所示:
    1、DEV-C++编译时报错“see previous definition of ‘AF_IPX’”、“warning C4005: ‘AF_IPX’ : macro redefinition”等等。
    报错原因:头文件Windows.h在winsock.h之前导入,Windows.h中包含了winsock.h,如果先导入windows.h,那么会导入和winsock2.h冲突的winsock.h,出现报错,头文件包含了2次读取,所以头文件里面的宏会重复定义。
    解决方法:头文件顺序变换,保证winsock.h在Windows.h之前,如下:
    #include <stdio.h>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <time.h>
    #include <windows.h>
    #include <string.h>
    #include <stdlib.h>
    #pragma comment(lib,“ws2_32.lib”)
    2、 CMD中使用gcc编译程序时报错“gcc不是内部或外部命令,也不是可运行的程序或批处理文件”,具体如下图所示:
    在这里插入图片描述
    报错原因:没有gcc编译器,gcc编译器是Linux平台下的,Windows平台本身不支持。
    解决办法:可以在DEV-C++下编译成功形成exe文件直接在cmd中运行,或者下载安装MinGW,MinGW 提供了一套简单方便的Windows下的基于GCC 程序开发环境,安装后配置好环境变量即可成功编译目标程序。
    3、在编译时出现报错,具体如下图所示:
    在这里插入图片描述
    报错原因:编译时没有指定链接到socket库
    解决办法:编译的时候在编译语句后面加上-lws2_32,指定链接到socket库即可。
    4、系统运行时Socket创建失败,具体情况如下图所示:
    在这里插入图片描述
    错误原因:使用WSAGetLastError()函数捕获错误原因,返回值为10013,表示以一种访问权限不允许的方式做了一个访问套接字的尝试。经过网上查找资料后发现由于设置了IP_HDRINCL选项,所以必须拥有administrator权限去运行系统。
    解决办法:以管理员方式运行cmd,再运行程序即可。
    经过多次调试,成功在界面输出“send ok!”,成功运行结果如下图所示:
    在这里插入图片描述

    为了验证是否成功发送,使用WireShark进行捕获,成功捕获到数据包,需求全部成功实现,捕获结果、携带数据如下图所示:
    在这里插入图片描述
    在这里插入图片描述

    结论评价

    本系统成功地完成对TCP数据包的填充和发送。对TCP 数据包进行填充要求我们充分了解它的数据结构以及相应字节上应该存放的内容和它们的功能。在数据正确性与合法性上,TCP用校验和函数来检验数据是否有错误,在发送和接收时都要计算校验和。在保证可靠性上,采用超时重传机制。在实现TCP数据包的发送中用到rawSocket来进行自定义IP报文的源地址,使用sendto()函数发送数据包。
    windows从winxp sp2开始便对raw socket进行了限制,所以raw socket只有在Linux平台上才能发挥它本该有的全部功能。如果有条件和时间最好在Linux上实现。并且此次系统设计只考虑到了服务端的发送,并没有考虑接收端接受的问题,只是完成了基本需求,还可以更进一步,使用C/S模式完成,使服务器端和客户端能够进行交互,使系统更加完整,更能体现出TCP可靠传输的特性和实现方式,也能更加清楚了解到Socket网络编程的全部步骤,对其中一些功能函数也能够更加熟悉。
    总体而言,本系统成功实现基本需求,但是还可以完善进步,改进空间还很大。大家可以考虑按上面所做的完善这个系统,工作量可能还是有点大,基本是要重新做,但是有了这个已经做好的系统的基础上手开发会快非常多。

    源代码

    #include <stdio.h> 
    #include <winsock2.h>    //Windows的TCP/IP网络编程接口(API),就相当于连接系统和你使用的软件之间交流的一个接口     
    #include <ws2tcpip.h> 
    #include <time.h>
    #include <windows.h>     //Windows.h中包含了winsock.h,如果先导入windows.h,那么会导入和winsock2.h冲突的winsock.h,出现报错,头文件包含了2次读取,所以头文件里面的宏会重复定义 
    #include <string.h>
    #include <stdlib.h>   
    #pragma comment(lib,"ws2_32.lib")
    
    #define IPVER   4           //IP协议预定
    #define MAX_BUFF_LEN 65500  //发送缓冲区最大值
    
    typedef struct ip_hdr    //定义IP首部 
    {
    	UCHAR h_verlen;            //4位首部长度,4位IP版本号 
    	UCHAR tos;                //8位服务类型TOS 
    	USHORT total_len;        //16位总长度(字节) 
    	USHORT ident;            //16位标识 
    	USHORT frag_and_flags;    //3位标志位和13位偏移大小 
    	UCHAR ttl;                //8位生存时间 TTL 
    	UCHAR proto;            //8位协议 (TCP, UDP 或其他) 
    	USHORT checksum;        //16位IP首部校验和 
    	ULONG sourceIP;            //32位源IP地址 
    	ULONG destIP;            //32位目的IP地址 
    }IP_HEADER; 
    
    typedef struct tsd_hdr //定义TCP伪首部 
    { 
    	ULONG saddr;    //源地址
    	ULONG daddr;    //目的地址 
    	UCHAR mbz;        //
    	UCHAR ptcl;        //协议类型 
    	USHORT tcpl;    //TCP长度 
    }PSD_HEADER; 
    
    typedef struct tcp_hdr //定义TCP首部 
    { 
    	USHORT th_sport;            //16位源端口 
    	USHORT th_dport;            //16位目的端口 
    	ULONG th_seq;                //32位序列号 
    	ULONG th_ack;                //32位确认号 
    	UCHAR th_lenres;            //4位首部长度/6位保留字 
    	UCHAR th_flag;                //6位标志位 
    	USHORT th_win;                //16位窗口大小 
    	USHORT th_sum;                //16位校验和 
    	USHORT th_urp;                //16位紧急数据偏移量 
    }TCP_HEADER; 
    
    
    
    
    //CheckSum:计算校验和的子函数 
    USHORT checksum(USHORT *buffer, int size) 
    { 
        unsigned long cksum=0; 
        while(size >1) 
        { 
            cksum+=*buffer++; 
            size -=sizeof(USHORT); 
        } 
        if(size) 
        { 
            cksum += *(UCHAR*)buffer; 
        } 
    
        cksum = (cksum >> 16) + (cksum & 0xffff); 
        cksum += (cksum >>16); 
        return (USHORT)(~cksum); 
    } 
    
    int main(int argc, char* argv[]) 
    { 
        WSADATA WSAData;   //一类数据结构,存放windows socket初始化信息 
        SOCKET sock;      
    	//socket()函数创建一个能够进行网络通信的套接字,对于TCP/IP协议族,该参数置AF_INET,第二个参数指定要创建的套接字类型,第三个参数指定应用程序所使用的通信协议 
    	//该函数如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET。套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符,另一个字段存放套接字数据结构的地址,因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。 
        //一般编程中并不直接针对sockaddr数据结构操作,而是使用另一个与sockaddr等价的数据结构,sockaddr_in,其结构体如下: 
    	    //sin_family指代协议族,在socket编程中只能是AF_INET
            //sin_port存储端口号(使用网络字节顺序)
            //sin_addr存储IP地址,使用in_addr这个数据结构
            //sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
            
        IP_HEADER ipHeader; 
        TCP_HEADER tcpHeader; 
        PSD_HEADER psdHeader; 
    
        char Sendto_Buff[MAX_BUFF_LEN];  //发送缓冲区
        unsigned short check_Buff[MAX_BUFF_LEN]; //检验和缓冲区
        const char tcp_send_data[]={"This is my homework of networt,I am happy!"};
    
        BOOL flag; 
        int rect,nTimeOver; 
        
    //    BOOL Flag=TRUE; 
    //    setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&Flag, sizeof(Flag));
    //    int timeout=1000;
    //    setsockopt(sock, SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));
    
        if (argc!= 5) 
        {
            printf("Useage: sendtcp soruce_ip source_port dest_ip dest_port \n"); 
            return false; 
        } 
    
        if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0) 
    	//第一个参数Windows Sockets API提供的调用方可使用的最高版本号
    	//第二个参数指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节.
    	//函数允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节,应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数. 
        { 
            printf("WSAStartup Error!\n"); 
            return false; 
        } 
    	if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET) 
    	//socket必须是raw socket才能发送自定义的数据包
    	//WSASocket()的发送操作和接收操作都可以被重叠使用。接收函数可以被多次调用,发出接收缓冲区,准备接收到来的数据。发
    	//送函数也可以被多次调用,组成一个发送缓冲区队列。可是socket()却只能发过之后等待回消息才可做下一步操作
    	//创建一个与指定传送服务提供者捆绑的套接口,可选地创建和/或加入一个套接口组。其功能都是创建一个原始套接字 
    	//af:[in]一个地址族规范。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。
    	//type:新套接口的类型描述。
        //protocol:套接口使用的特定协议,这里IPPROTO_RAW,表示这个socket只能用来发送IP包,而不能接收任何的数据。发送的数据需要自己填充IP包头,并且自己计算校验和。
    	//IPPROTO_IP为用于接收任何的IP数据包。其中的校验和和协议分析由程序自己完成。 
        //lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略,可以为空。
        //g:保留给未来使用的套接字组。套接口组的标识符。
    	//iFlags:套接口属性描述 ,WSA_FLAG_OVERLAPPED表明可以使用发送接收超时设置。 
    	//该函数如果调用成功就返回新创建的套接字的描述符,如果失败就返回INVALID_SOCKET。 
        { 
            printf("Socket Setup Error!\n"); 
            printf("send error:%d\n", WSAGetLastError());
            return false; 
        } 
        flag=true; 
    	//设置选项值  IP_HDRINCL为要设置的选项值
        if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))==SOCKET_ERROR) 
        // 获取或者设置与某个套接字关联的选项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。
    	//当操作套接字选项选项位于的层和选项的名称必须给出。为了操作套接字层的选项,应该将层的值指定为SOL_SOCKET。为了操作其它层的选项,控制选项的合适协议号必须给出。 
    	    //sock:将要被设置或者获取选项的套接字。
            //level:选项所在的协议层。
            //optname:需要访问的选项名。
            //optval:指向包含新选项值的缓冲。
            //optlen:现选项的长度 
        //这里表示为操作一个由IP协议解析的代码,所以层应该设定为IP层。即 IPPROTO_IP,设置的控制的方式(选项值)为IP_HDRINCL,意思为在数据包中包含IP首部,表明自己来构造IP头。
    	//注意,如果设置IP_HDRINCL选项,那么必须拥有administrator权限。 
    	{ 
            printf("setsockopt IP_HDRINCL error!\n"); 
            return false; 
        } 
        nTimeOver=1000; 
    	//设置选项值  SO_SNDTIMEO为要设置的选项值
        if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR) 
        { 
            printf("setsockopt SO_SNDTIMEO error!\n"); 
            return false; 
        } 
        //在send()过程中有时由于网络状况等原因,发送不能预期进行,而设置收发时限,在这里我们使用基本套接字SOL_SOCKET,设置SO_SNDTIMEO表示使用发送超时设置,超时时间设置为1000ms 
        //经过一次性设置后,以后调用send系列的函数,最多只能阻塞 1 秒 
        
        //填充IP首部 
        ipHeader.h_verlen=(IPVER<<4 | sizeof(ipHeader)/sizeof(unsigned long));  
        ipHeader.tos=(UCHAR)0; 
        ipHeader.total_len=htons((unsigned short)sizeof(ipHeader)+sizeof(tcpHeader)+sizeof(tcp_send_data)); 
        ipHeader.ident=0;       //16位标识,用来标识是否分片。 
        ipHeader.frag_and_flags=0; //3位标志位,最低位为MF,0则表示后面没有分片了,DF表示不能分片,分片时置为1。 
        ipHeader.ttl=128; //8位生存时间  
        ipHeader.proto=IPPROTO_UDP; //协议类型,协议类型是什么就交给哪个协议进行处理 
        ipHeader.checksum=0; //检验和暂时为0
        ipHeader.sourceIP=inet_addr(argv[1]);  //32位源IP地址
        ipHeader.destIP=inet_addr(argv[3]);    //32位目的IP地址
        //inet_addr() 函数的作用是将点分十进制的IPv4地址转换成网络字节序列的长整型,将高位和地位交换 
    	//网络字节序定义:收到的第一个字节被当作高位看待,这就要求发送端发送的第一个字节应当是高位。a.b.c.d先发送a,再b、c、d。 
        
    	//计算IP头部检验和
        memset(check_Buff,0,MAX_BUFF_LEN);
        //将一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化,此处是将check_buff全部初始化为‘0’ 
        memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER));
        //用做内存拷贝,可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度,strcpy只能拷贝字符串,遇到'/0'就结束拷贝
        ipHeader.checksum=checksum(check_Buff,sizeof(IP_HEADER));
        
    
        //构造TCP伪首部
        psdHeader.saddr=ipHeader.sourceIP;
        psdHeader.daddr=ipHeader.destIP;
        psdHeader.mbz=0;
        psdHeader.ptcl=ipHeader.proto;
        psdHeader.tcpl=htons(sizeof(TCP_HEADER)+sizeof(tcp_send_data));  //将主机的无符号短整形数转换成网络字节顺序,简单地说,htons()就是将一个数的高低位互换
    
        //填充TCP首部 
        tcpHeader.th_dport=htons(atoi(argv[4])); //16位目的端口号,atoi()函数用于把字符串转换成整型数,函数会扫描参数字符串,跳过前面的空白字符(例如空格,tab缩进)等,直到遇上数字或正负符号才开始做转换,而在遇到非数字或字符串结束符('\0')才结束转换,并将结果返回 
        tcpHeader.th_sport=htons(atoi(argv[2])); //16位源端口号 
        tcpHeader.th_seq=0;                         //SYN序列号
        tcpHeader.th_ack=0;                         //ACK序列号置为0
        //TCP首部的长度和保留位
        tcpHeader.th_lenres=(sizeof(tcpHeader)/sizeof(unsigned long)<<4|0); 
        tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是//FIN,16是ACK探测 等等 
        tcpHeader.th_win=htons((unsigned short)8192);     //窗口大小
        tcpHeader.th_urp=0;                            //紧急指针,指出本报文段中的紧急数据的字节数    
        tcpHeader.th_sum=0;                            //检验和暂时填为0
        
        //计算TCP校验和 
        memset(check_Buff,0,MAX_BUFF_LEN);
        memcpy(check_Buff,&psdHeader,sizeof(psdHeader)); 
        memcpy(check_Buff+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader));    //直接从 check_Buff+sizeof(psdHeader)出开始,数组名的值是个指针常量,也就是数组第一个元素的地址。 
        memcpy(check_Buff+sizeof(PSD_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));
        tcpHeader.th_sum=checksum(check_Buff,sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data)); 
    
        //填充发送缓冲区
        memset(Sendto_Buff,0,MAX_BUFF_LEN);
        memcpy(Sendto_Buff,&ipHeader,sizeof(IP_HEADER));
        memcpy(Sendto_Buff+sizeof(IP_HEADER),&tcpHeader,sizeof(TCP_HEADER)); 
        memcpy(Sendto_Buff+sizeof(IP_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));
        int datasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data);
        
        //发送数据报的目的地址
        SOCKADDR_IN dest;    
        memset(&dest,0,sizeof(dest));
        dest.sin_family=AF_INET; 
        dest.sin_addr.s_addr=inet_addr(argv[3]); //inet_addr() 函数的作用是将点分十进制的IPv4地址转换成网络字节序列的长整型,将高位和地位交换 
        dest.sin_port=htons(atoi(argv[4]));
    	rect=sendto(sock,Sendto_Buff,datasize, 0,(struct sockaddr*)&dest, sizeof(dest)); 
    	if (rect==SOCKET_ERROR) 
    	{  
          printf("send error!:%d\n",WSAGetLastError()); 
          return false; 
        } 
        else 
        printf("send ok!\n");
        closesocket(sock);    //关闭套接口,释放套接描述字 
        WSACleanup();   //解除与Socket库的绑定并且释放socket库所占的系统资源 
        return 1; 
    
    }
    
    

    总结

    源码给大家做了很多注释,方便理解,已经非常非常简单易懂了,如果还有疑问可以留言或私信,希望能帮到大家。

    展开全文
  • Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密 Java非对称...
  • TCP/UDP测试工具是运行于Windows操作系统上的一种网络协议及数据包测试和调试工具,支持以16进制发送和接收数据,可随时进行16进制切换,支持在收到消息时自动应答,数据可定义设置,支持UDP广播,支持保存设置好的...
  • 先把服务端与客户端的连接代码敲出来 服务端 IPAddress ip = new IPAddress...TcpListener server = new TcpListener(ip, 8005); server.Start();//服务端启动侦听 TcpClient client = server.AcceptTcpClient();...

    先把服务端与客户端的连接代码敲出来

    服务端
    IPAddress ip = new IPAddress(new byte[] { 127, 1, 1, 1 });
    TcpListener server = new TcpListener(ip, 8005);
    server.Start();//服务端启动侦听
    TcpClient client = server.AcceptTcpClient();//接受发起连接对象的同步方法
    Console.WriteLine("收到客户端连接请求")//如果没有客户端请求连接,这句话是无法Print out的
    客户端
    IPAddress ip=IPAddress.Parse("127.1.1.1");
    TcpClient client=new TcpClient();
    client.Connect(ip,8005);//8005端口号,必须与服务端给定的端口号一致,否则天堂无门

    先看看服务端的特殊标记的那句代码

    AcceptTcpClient() 这个方法是一个同步方法,在没有接受到连接请求的时候,位于它下面的代码是不会被执行的,也就是线程阻塞在这里,进行不下去了,想出城没有城防长官的批复是不能的,嘿嘿...

    连接后,客户端要发送数据给服务端,先贴代码再说

    NetworkStream dataStream=client.GetStream();
    string msg="服务端亲启!";
    byte[] buffer=Encoding.default.getBytes(msg);
    stream.write(buffer,0,buffer.length);
    //这段代码呈接上面那段客户端代码

    NetworkStream 在网络中进行传输的数据流,也就是说传输数据必须写入此流中,才能够互通有无。
    首先客户端先获取用于发送信息的流,然后将要发送的信息存入byte[] 数组中(数据必须是byte[] 才能够写入流中),最后就是写入传输的数据流,发送

    聪明的你想必已经知道如何在服务端获取数据了
    既然客户端费力的把数据包装发给服务端了,那么服务端自然要把包装拆了,得到数据,上代码:

    NetworkStream dataStream=client.GetStream();
    byte[] buffer=new byte[8192];
    int dataSize=dataStream.Read(buffer,0,8192);
    Console.write(Encoding.default.GetString(buffer,0,dataSize));
    //这段代码呈接上面那段服务端代码

    代码一写,我觉得再说多余了,不过还要在说一两句,嘿嘿
    Read() 方法需要三个参数,1,存储数据的缓存空间。2,写入数据的起始点就是从存储空间的什么位置开始写入数据。3,就是存储空间的大小。返回写入数据的大小值
    Encoding.default.GetString() 参数解析
    1,存储数据的缓存空间。2,从什么位置开始接收数据。3,接收多少数据

    以上只是再简单不过的数据发送,而且只是客户端发给服务端,只能发一条信息而已,那如果想彼此互发,并且想发多少条信息都可以,怎么办呢

     

    首先基于以上的代码,编写一个winform的小程序

    界面很简单,要实现的功能就是客户端与服务端互发信息。

    感觉还是直接上代码吧

    服务端的全部代码如下: 

    using hepu.BloodModel;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace hepu
    {
        public partial class Blood5_TCP : Form
        {
            public Blood5_TCP()
            {
                InitializeComponent();
            }
            public delegate void showData(string msg);//委托,防止跨线程的访问控件,引起的安全异常
            private const int bufferSize = 8000;//缓存空间
            private TcpClient client;
            private TcpListener server;
            /// <summary>
            /// 结构体:Ip、端口
            /// </summary>
            struct IpAndPort
            {
                public string Ip;
                public string Port;
            }
    
            private void Blood5_TCP_Load(object sender, EventArgs e)
            {
               
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                if (txtIP.Text.Trim() == string.Empty)
                {
                    return;
                }
                if (txtPort.Text.Trim() == string.Empty)
                {
                    return;
                }
    
                Thread thread = new Thread(reciveAndListener);
                //如果线程绑定的方法带有参数的话,那么这个参数的类型必须是object类型,所以讲ip,和端口号 写成一个结构体进行传递
                IpAndPort ipHePort = new IpAndPort();
                ipHePort.Ip = txtIP.Text;//服务器IP
                ipHePort.Port = txtPort.Text;//为程序设置端口
    
                thread.Start((object)ipHePort);
            }
            /// <summary>
            /// 侦听客户端的连接并接收客户端发送的信息
            /// </summary>
            /// <param name="ipAndPort">服务端Ip、侦听端口</param>
            private void reciveAndListener(object ipAndPort)
            {
                IpAndPort ipHePort = (IpAndPort)ipAndPort;
    
                IPAddress ip = IPAddress.Parse(ipHePort.Ip);
                server = new TcpListener(ip, int.Parse(ipHePort.Port));
                server.Start();//启动监听
                rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端开启侦听....\n");
                //  btnStart.IsEnabled = false;
    
                //获取连接的客户端对象
                client = server.AcceptTcpClient();
                rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "有客户端请求连接,连接已建立!");//AcceptTcpClient 是同步方法,会阻塞进程,得到连接对象后才会执行这一步  
    
                //获得流
                NetworkStream reciveStream = client.GetStream();
    
                #region 循环监听客户端发来的信息
    
                do
                {
                    byte[] buffer = new byte[bufferSize];
                    int msgSize;
                    try
                    {
                        lock (reciveStream)
                        {
                            msgSize = reciveStream.Read(buffer, 0, bufferSize);
                        }
                        if (msgSize == 0)
                            return;
                        string msg = Encoding.Default.GetString(buffer, 0, bufferSize);
                        TextBox1.text=msg;//接收到的信息放到textBox里
    
                        //rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "\n客户端曰:" + result + "\r\n");
                    }
                    catch (Exception ex)
                    {
                        server.Stop();
                        string aa = ex.Message;
                        MessageBox.Show(aa);
                        rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "\n 出现异常:连接被迫关闭");
                        break;
                    }
                } while (true);
    
                #endregion
            }
     /// <summary>
            /// 将数据包转换成xml格式   提取有效参数
            /// </summary>
            /// <param name="hl7data"></param>
            /// <returns></returns>
            public NewBlood5  FormatXml(string hl7data)
            {
                XmlDocument xmlObject = HL7ToXmlConverter.ConvertToXmlObject(hl7data);
                NewBlood5 blood5 = new NewBlood5();//实体类
                //根据node去获取需要的数据
                blood5.Brcode = HL7ToXmlConverter.GetText(xmlObject, "MSH/MSH.54", 0);
                blood5.WBC = HL7ToXmlConverter.GetText(xmlObject, "MSH/MSH.662", 0);
    
                return blood5;
            }
        }
    }

    客户端代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace Blood
    {
        public partial class TCP : Form
        {
            public TCP()
            {
                InitializeComponent();
            }
            TcpClient client;
            private const int bufferSize = 8000;
            NetworkStream sendStream;
            public delegate void showData(string msg);
            private void TCP_Load(object sender, EventArgs e)
            {
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                if (txtIP.Text.Trim() == string.Empty)
                {
                    return;
                }
                if (txtPort.Text.Trim() == string.Empty)
                {
                    return;
                }
                IPAddress ip = IPAddress.Parse(txtIP.Text);
                client = new TcpClient();
                client.Connect(ip, int.Parse(txtPort.Text));
                rtbtxtShowData.AppendText("开始连接服务端....\n");
                rtbtxtShowData.AppendText("已经连接服务端\n");
                //获取用于发送数据的传输流
                sendStream = client.GetStream();
                Thread thread = new Thread(ListenerServer);
                thread.Start();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                if (client != null)
                {
                    //要发送的信息
                    if (txtSendMsg.Text.Trim() == string.Empty)
                        return;
                    string msg = txtSendMsg.Text.Trim();
                    //将信息存入缓存中
                    byte[] buffer = Encoding.Default.GetBytes(msg);
                    //lock (sendStream)
                    //{
                    sendStream.Write(buffer, 0, buffer.Length);
                    //}
                    rtbtxtShowData.AppendText("发送给服务端的数据:" + msg + "\n");
                    txtSendMsg.Text = string.Empty;
                }
            }
            private void ListenerServer()
            {
                do
                {
                    try
                    {
                        int readSize;
                        byte[] buffer = new byte[bufferSize];
                        lock (sendStream)
                        {
                            readSize = sendStream.Read(buffer, 0, bufferSize);
                        }
                        if (readSize == 0)
                            return;
                        rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端曰:" + Encoding.Default.GetString(buffer, 0, readSize) + "\n");
    
                    }
                    catch
                    {
                        rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "报错");
                    }
                    //将缓存中的数据写入传输流
                } while (true);
            }
        }
    }

     其中用到了,多线程处理还有委托,因为以上我们用到的不管是Connect,还是AcceptTcpClient方法 都是同步方法,会阻塞进程,导致窗口无法自由移动

     rtbtxtShowData.Invoke(new showData(rtbtxtShowData.AppendText), "服务端开启侦听....\n");

    Ok,至此客户端与服务端的数据传递就大功告成了,这只是一个很简单的操作,如果有多个客户端呢?要求异步通信,怎么办?不急,慢慢来,不积跬步无以至千里

    如果有什么错的,希望指正。

    展开全文
  • 软件测试面试题(面试前准备篇)

    万次阅读 多人点赞 2019-09-27 10:42:37
    设计测试用例时一般从以下几个方面进行分析:功能测试,性能测试,界面测试,安全性测试,兼容性测试,可用性测试,可靠性测试,本地化/国际化测试。 例子(另起一篇) 5、软件测试流程 公司严格规范测试...
  • Python 基础 之 网络 socket 使用 tcp (SOCK_STREAM)实现简单的客户端、服务端(消息发送和接收) 一、简单介绍 Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于...
  • · 在CSS中定义的宽度高度之外绘制元素的内边距边框 border-box · 在CSS中微元素设定的宽度高度就决定了元素的边框盒 · 即为元素在设置内边距边框是在已经设定好的宽度高度之内进行绘制 · CSS中...
  • 基于TCP流协议的数据包通讯

    千次阅读 2016-02-03 23:43:42
    TCP流式协议,举个简单例子,一端用send 分别发送 100,123,120字节的数据, 另一端用recv可以一下子接收到 100+123+120=343字节的数据,或者先接收 3个字节的数据,再接收余下的340字节, 不管另一端怎么接收,最终...
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    架构师,开发工程师写出《概要设计说明书》High-level design(HLD) 内容:系统程序中的模块,子模块他们之间的关系接口 测试的工作:对HLD进行测试评审A集成测试计划《集成测试计划书》B集成测试设计《集成...
  • 软件测试面试题汇总

    万次阅读 多人点赞 2018-09-27 12:31:09
    28、软件配置管理工作开展的情况认识? ................................................................................................. 9 29、你觉得软件测试通过的标准应该是什么样的? ................
  • TCP报文发送工具

    千次阅读 2016-10-15 23:18:00
    该工具用于向Socket服务端发送XML报文,软件功能界面如下图所示: 配置好IP端口后,单击“载入报文文件”按钮,在文件选择对话框中选择报文文件,如图: 报文文件打开后,可在右侧编辑框中对报文进行编辑,...
  • Unity与UDP协议字符串图片的发送和接收!一:UDP前言二:测试  1;导入资源测试  2;自己操作测试三:完成与支持 本文提供详细教程记录遇到的难点并帮助同行的朋友们坚持以最简单的方法...
  • Linux初学者面试问题 Linux基本面试问题 ...这是一个用户友好的环境,他们可以在其中轻松修改创建源代码的变体。 2.谁发明了Linux?解释Linux的历史? 回答:Linus Torvalds创建了Linux。莱纳斯·...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非...
  • 单个TCP包每次打包1448字节的数据进行发送(以太网Ethernet最大的数据帧是1518字节,以太网帧的帧头14字节帧尾CRC校验4字节  seq编码,在RFC793中,建议ISN一个假的时钟绑在一起,这个时钟会在每4微秒对...
  • scapy构造数据包总结

    千次阅读 2019-09-18 15:07:03
    send() 只发送而不接收数据包,并且网络层之下的都默认处理好了,只需传给它网络层之上(包括网络层)的参数即可 sendp() 只发送接收,并且数据链路层之下的都处理好了,只需传给它数据链路层之上(包括数据联络...
  • 我用VC6.0MFC编写的一个TCP文件传输程序异步版,Windows界面版WSAAsyncSelect模型的程序,能自动接收文件,当服务端发送文件时,客户端将自动弹出确认框,询问是否接收文件,如果点击是,则自动弹出保存文件对话框...
  • Tomcat面试题+http面试题+Nginx面试题+常见面试题

    千次阅读 多人点赞 2019-12-12 15:04:43
    如果深入一点的话,就是nginx的特殊进程模型事件模型的设计,才使其可以实现高并发。 进程模型 它是采用一个master进程多个worker进程的工作模式。 1、master进程主要负责收集、分发请求。当一个请求过来时,...
  • sokit测试UDP、TCP工具

    2019-03-06 13:56:57
    tcp数据包近日推出了1.3版本,修复了若干bug,提升了软件使用的流畅性,加上美观的界面,sokit TCP/UDP 数据包收发测试(调试)工具(Win32)新版一定能给用户带来一个更好的体验。  支持收发日志文件。 支持快捷键...
  • TCP UDP测试工具

    2018-10-11 11:45:25
    该工具可发送和接收TCP,UDP数据。主要用于在网络通讯程序开发时,测试TCP或UDP通讯连接和测试数据的接收和发送情况。该工具通过直观友好的界面实时展示发送和接收的数据。 功能: 1.支持TCP协议发送和接收数据。...
  • Qt tcp实现文件发送

    千次阅读 2020-04-10 18:04:20
    与UDP不同,它是面向连接数据流的可靠传输协议。也就是说,它能使一台计算机上的数据无差错的发往网络上的其他计算机,所以当要传输大量数据时,我们选用TCP协议。 TCP协议的程序使用的是客户端/服务器(C/S)模式...
  • 基于NB-IoT的智能停车系统——简单搭建1 产品功能2 基本原理2.1 磁阻传感器AMR2.2 NB-IoTSTM32单片机模块2.3 Java应用程序与MySQL数据库3 功能实现3.1 前端采集3.2 信息处理3.3 数据管理4 总结与展望 1 产品功能 ...
  • 本次计算机网络课程设计是基于TCP协议网上聊天程序,程序中用到了套接字socket、多线程threadPython自带的图形界面库Tkinter,在密码保存传递方面用到了MD5算法,该程序的功能:用户注册、用户登录、显示在线...
  • (2) 捕捉数据包,验证数据帧、IP数据报、TCP数据段的报文格式。 (3) 捕捉并分析ARP报文。 (4) 捕捉ping过程中的ICMP报文, 分析结果各参数的意义。 (5) 捕捉tracert过程中的ICMP报文,分析跟踪的路由器IP是...
  • TCP/UDP测试工具是运行于Windows操作系统上的一种网络协议及数据包测试和调试工具,支持以16进制发送和接收数据,可随时进行16进制切换,支持在收到消息时自动应答,数据可定义设置,支持UDP广播,支持保存设置好的...
  • 写在开篇,最近因为测试需求,要使用Linux虚机模拟tcp/udp等协议报文,网上一搜,工具很多,文档不少,看着也不难,结果一装一堆报错,令人头秃。。。 最后翻到这篇文章真的是太绝了,瞬间解决安装报错问题,也才...
  • TCP/IP,TCP,UDP,IP,Socket 概述 什么是 TCP/IP? TCP,UDP 有什么区别? 什么是 Socket? 网上这方面的资料有很多,但都很琐碎,没有系统化,要么看完很快就忘记了,要么就是看完迷迷糊糊似懂非懂,下面...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,066
精华内容 9,626
关键字:

发送和接收tcp数据包界面设计