.NET下使用Socket进行TCP传输时数据发送或接收不全

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.NET下使用Socket进行TCP传输时数据发送或接收不全相关的知识,希望对你有一定的参考价值。

程序是一个基本的CS模型,客户端发送请求给服务器,服务器处理完毕以后把响应发回客户端。

1. 因为一次TCP连接只有一个请求或响应需要进行发送或接收,因此只想设计为发送请求之后服务器全部接收完毕即可,没有预先传一个包含待传的字节数的小型数据头。
2. 同时考虑到TCP流的特性,接收数据一次可能接收不完,故设计了循环多次接收。

客户端:先发送请求、再接收响应,关键部分代码如下:
MySocket.Connect( ipe );//连接到服务器
byte[] dataToEncrypt = Encoding.UTF8.GetBytes( message );
MySocket.Send( dataToEncrypt, dataToEncrypt.Length, SocketFlags.None );

byte[] recvBytes = new byte[ 102400 ];
int offset = 0;
int availableSize = 102400;
do
int bytesAmount = MySocket.Receive( recvBytes, offset, availableSize, SocketFlags.None );
offset += bytesAmount;
availableSize -= bytesAmount;
while ( MySocket.Available > 0 && availableSize > 0 );
string rcvMsg = Encoding.UTF8.GetString( recvBytes, 0, offset );

服务器:先接收请求,再发送响应,关键部分代码如下:
Socket tempSocket = (Socket) socket;
byte[] recvBytes = new byte[ 102400 ];
int offset = 0;
int availableSize = 102400;
tempSocket.ReceiveTimeout = 1000;
do
int bytesAmount = tempSocket.Receive( recvBytes, offset, availableSize, SocketFlags.None );
offset += bytesAmount;
availableSize -= bytesAmount;
while ( tempSocket.Available > 0 && availableSize > 0 );
string msg = Encoding.UTF8.GetString( recvBytes, 0, offset );

string decodedRequest = Coding.DecodeForTimes( msg, 5 );
string response = UndertakeWork.ScheduleRequest( decodedRequest ); //处理请求并返回结果
byte[] respondBytes = Encoding.UTF8.GetBytes( response );
tempSocket.Send( respondBytes, respondBytes.Length, SocketFlags.None );

tempSocket.Close();

具体情况是,用于缓存发送和接收请求的byte数组都是100K,保证能完全容纳程序的通信量。(当然每次发送也不是100K全发出去啦=_=)
由于对数据进行了多次DES加密,请求最后有38700 bytes左右,但是每次在服务器端接收只能收到18800 bytes左右。

弄一下午没办法了= = 求解决办法……谢谢了……
= =对了对了,还有问题是一旦我用VS进行调试时,一次次按F10检查,3W8 bytes数据就一定能接收完全,而一旦我取消了所有断点直接让程序跑的时候就只能接收到1W8……

唔,传输性能现在先不用管,只要能把数据弄全就行……

参考技术A 试下引入多线程吧.

让服务器返回一个信息, 告诉客户端可以开始传数据之后, 客户端再传, 之前服务器端开一个线程来接收数据.

你还可以检测收到的1W8数据是3W8里面的哪一部分. 这个把发送的数据和接收的数据都保存成文件, 然后用WinHex打开就能很容易查找到. 这样才知道丢的是哪部分, 然后按情况处理.

TCP/IP协议的一个具体实现Socket

java 中Socket的用法

TCP/IP协议

两个不同的协议,放在一起说。IP协议是用来查找地址的,对应网际互连层;TCP协议是用来规范传输规则的,对应传输层。

TCP在传输之前会进行三次沟通(三次握手),传完数据断开的时候会进行四次沟通(四次挥手)

两个序号和三个标志位

seq(sequence number)表示所传数据的序号;TCP传输时每一个字节都由一个序号,发送数据时会将数据的第一个序号发送给对方,接收方会按序号检查数据是否接收完整了。(如不完整,则重新发送)

ack(acknoledgement number)表示确认号,接收端用它来给发送端反馈已经成功接收到的数据的信息,它的值为希望接收的下一个数据包起始序号(该序号值前面的数据已经接收到了)

ACK:确认位,只有ACK=1时,ack才起作用。 正常通信时ACK=1,第一次发起请求时因为没有需要确认接收的数据(ACK=0)

SYN:同步位,用于在建立连接时同步序号。当接收端接收到SYN=1报文时会直接将ack设置为接收到的seq+1的值

SYN会在前两次握手时都为1(通信的双方的ack都需要设置一个初始值)

FIN:终止位,用来在数据传输完毕后释放连接

TCP传输是双全工模式,传输双方是对等的,可以同时传输数据。

四次挥手就是双方分别发送FIN标志来关闭连接并让对方确认。

 

传输层的协议还有UDP(TCP有连接,UDP没有连接,UDP拿到地址后直接传输,速度快,不可靠。通常视频传输、语音传输等对完整性要求不高的且对速度要求高、数据量大的通信多使用UDP;邮件,网页一般使用TCP协议)

 

java中网络通信是通过Socket实现的;分为ServerSocket(在服务端,通过accept()监听请求,监听到请求后返回Socket对象)和Socket(用于具体完成数据传输,在客户端直接使用Socket发起请求并传输数据)

 

ServerSocket的使用分三步:

一.创建ServerSocket    有5个构造方法,最方便的是ServerSocket(int port){  }  只需一个端口号即可

二.ServerSocket.accept()进行监听,该方法是阻塞方法(调用后程序会停下来等待连接请求,在接收到请求之前程序不会继续走下去;当接收到请求后该方法会返回一个Socket对象)

三.使用accept()方法返回的Socket与客户端进行通信。

技术分享图片

简单示例:

 1 import java.io.*;
 2 import java.net.ServerSocket;
 3 import java.net.Socket;
 4 
 5 public class Server{
 6      public static void main(String args[]){
 7            try{
 8                 //创建一个ServerSocket监听8080端口
 9         Serversocket server=new ServerSocket(8080);
10                 //等待请求
11         Socket socket=server.accept();
12             //接收到请求后使用socket进行通信
13             BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
14         String line=br.readLine();
15         System.out.println("从客户端接收信息:"+line);
16         //创建PrintWriter,用于发送数据
17         PrintWriter pw=new PrintWriter(socket.getOutputStream());
18         pw.println("发送数据:"+line);
19         pw.flush();
20         pw.close();
21         br.close();
22         socket.close();
23         server.close();
24         }catch(Exception e){
25             e.printStackTrace();
26         }
27     }      
28 }                    

 

客户端Socket

选择Socket(String host,int port)构造方法传入目标主机的地址和端口,其创建过程就会与服务端建立连接。

 1 import java.io.*;
 2 import java.net.Socket;
 3 
 4 public class Client{
 5     public static void main(String args[]){
 6         String msg="客户端要传的数据......";
 7         try{
 8             //创建一个Socket,和本机的8080端口连接
 9             Socket socket=new Socket("127.0.0.1",8080);
10             //使用Socket创建PrintWriter和Bufferedreader读写数据
11             PrintWriter pw=new PrintWriter(socket.getOutputStream());
12             BufferedReader bf=new BufferedReader(new InputStreamReader(socket.getInputStream()));
13             //发送数据
14             pw.println(msg);
15             pw.flush();
16             //接收数据
17             String line=br.readLine();
18             System.out.println("从服务端接收数据:"+line);
19             //关闭资源
20             pw.close();
21             br.close();
22             socket.close();
23         }catch(Exception e){
24                 e.printStackTrace();
25         }
26     }
27 }

 

先启动Server,在启动Client就可完成一次通信。

 

以上是关于.NET下使用Socket进行TCP传输时数据发送或接收不全的主要内容,如果未能解决你的问题,请参考以下文章

TCP/IP协议的一个具体实现Socket

两类传输协议:TCP,UDP

C++基于TCP和UDP的socket通信

http与socket和https的区别

Socket编程

网络编程Socket