Linux C语言 CS程序,客户端发送的数据和服务器端接收到的数据不一样,求解

Linux C语言 CS程序,客户端发送的数据和服务器端接收到的数据不一样,求解,第1张

估计你是用的tcp

socket,导致“videlord”网友说的情况:对于tcp

socket,send与recv不是对等的,recv时只要缓冲有数据就会收上来。简单说就是你send

4次,比如分别为10

10

10

10字节,对端可以一次recv到这40字节数据,也可以recv

40次、每次1字节。

解决办法有两种:

1

改用udp

socket,send/recv自然对等了

2

继续用tcp

socket,自己进行数据分段:比如自行约定在数据前约定4个字节用于描述数据长度,这样发送时,send

4+33字节,send

4+35字节;接收时,先获取描述长度的4字节获得长度,再按照长度

接收数据

(可能需要多次recv凑齐指定长度)。

socket-client

----------------------------------------------

using System;

using SystemCollectionsGeneric;

using SystemComponentModel;

using SystemData;

using SystemDrawing;

using SystemText;

using SystemWindowsForms;

using SystemNet;

using SystemNetSockets;

using SystemThreading;

namespace socket_client

{

//客户端

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

ControlCheckForIllegalCrossThreadCalls = false;

}

Socket s;//聊天用

Thread th;

//连接

private void button1_Click(object sender, EventArgs e)

{

//步骤1 配置远程服务器信息

IPEndPoint removeServer = new IPEndPoint(IPAddressParse(textBox1Text), intParse(textBox2Text));

//步骤2 创建套接字

s = new Socket(AddressFamilyInterNetwork, SocketTypeStream, ProtocolTypeTcp);

//步骤3 套接字连接远程服务器

sConnect(removeServer);

//步骤4 提示连接状态

if (sConnected)

{

label4Text = "连接服务器成功!";

//步骤5 循环接收服务器发来的消息

th = new Thread(new ThreadStart(BB));

thIsBackground = true;

thStart();

}

}

void BB()

{

while (true)

{

byte[] bb = new byte[1024];

int i= sReceive(bb); //接收数据,返回每次接收的字节总数

string removeMsg = EncodingUnicodeGetString(bb,0,i);

if (removeMsg == "CMD--EXIT")//收到的是退出通知

{

label4Text = "无连接";

DialogResult re=MessageBoxShow("服务器已经关闭\n\"确定\"后退出程序,\n\"取消\"继续停留!", "消息提示:", MessageBoxButtonsOKCancel, MessageBoxIconWarning);

MessageBoxShow(reToString());

if (re == DialogResultOK)

{

sendExit();//告诉服务器我退出了

ApplicationExit();

}

return;

}

richTextBox1AppendText(removeMsg+"\n") ;

richTextBox1ScrollToCaret();

}

}

//发送消息

private void button3_Click(object sender, EventArgs e)

{

string msg = "客户端:" + richTextBox2Text;

byte[] bb = EncodingUnicodeGetBytes(msg);

sSend(bb);

richTextBox2Text = "";

richTextBox2Focus();

}

//发送“客户端退出提示”

void sendExit()

{

string cmd = "CMD--EXIT";

byte[] bb = EncodingUnicodeGetBytes(cmd);

sSend(bb);

}

}

}

socket-server

--------------------------------------------------------------

using System;

using SystemCollectionsGeneric;

using SystemComponentModel;

using SystemData;

using SystemDrawing;

using SystemText;

using SystemWindowsForms;

using SystemNet;

using SystemNetSockets;

using SystemThreading;

namespace socket_server

{

//服务器

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

ControlCheckForIllegalCrossThreadCalls = false; //可以调试时,不捕捉控件创建线程错误

}

Thread th;

Socket s1;//监听用

Socket s2;//聊天用

//监听

private void button1_Click(object sender, EventArgs e)

{

IPAddress ip = DnsGetHostEntry(DnsGetHostName())AddressList[0];

//步骤1 创建网络端点IPEndPoint

IPEndPoint myServer = new IPEndPoint(ip, 888);

//步骤2 创建套接字Socket

s1 = new Socket(AddressFamilyInterNetwork, SocketTypeStream, ProtocolTypeTcp);

//步骤3 套接字绑定到网络端点

s1Bind(myServer);

label1Text = ip+": 888 \n等待客户端连接";

th = new Thread(new ThreadStart(AA));

thIsBackground = true;

thStart();

}

void AA()

{

//步骤4 监听

s1Listen(5);

//步骤5 接受客户端连接

s2 = s1Accept();

//步骤6 判断连接状态

if (s2Connected)

{

label1Text = "已有客户端连接!";

//步骤7 循环接收客户端消息

while (true)

{

byte[] bb = new byte[1024];

int i= s2Receive(bb);

string removeMsg = EncodingUnicodeGetString(bb,0,i);

if (removeMsg == "CMD--EXIT")//收到的是退出通知

{

label1Text = "客户端已经取消了连接";

return;

}

richTextBox1AppendText( removeMsg+"\n" );

richTextBox1ScrollToCaret();

}

}

}

//停止监听

private void button2_Click(object sender, EventArgs e)

{

sendExit();//告诉客户端

s2Shutdown(SocketShutdownBoth);

s1Close();

thAbort();

label1Text = "无连接";

}

//发送消息

private void button3_Click(object sender, EventArgs e)

{

string msg = "服务器:" + richTextBox2Text;

byte[] bb = EncodingUnicodeGetBytes(msg);

s2Send(bb);

richTextBox2Text = "";

richTextBox2Focus();

}

//发送“服务器退出提示”

void sendExit()

{

string cmd = "CMD--EXIT";

byte[] bb = EncodingUnicodeGetBytes(cmd);

s2Send(bb);

}

}

}

就像人类的语言,使连接到网络的计算机可以互相通信,需要一套通用的通信标准符合性,这是网络协议,不同的计算机之间必须使用相同的通信协议进行通信。互联网的TCP / IP协议是最广泛使用的通信协议。 TCP / IP是英文的传输控制协议/互联网协议的缩写,意思是“传输控制协议/ Internet协议TCP / IP是一组协议(协议)互联网的使用

在互联网上。传输控制协议和互联网协议的工作是在互联网协议(IP)是负责从一台主机到另一台主机发送的消息。分为一个小袋子消息在传输过程中的安全。

BR />传输控制协议(TCP)负责收集这种信息包,并提出了相应的发送和接收,在接收端的序列,然后恢复。运输协议,以确保准确的数据包传输。

的 >

一、51单片机串口概念

1、51单片机的串行口

51单片机的串行口是一个可编程全双工的通信接口,具有UART(通用异步收发器)的全部功能。

2、51单片机的硬件连接

简单双向串口通信有两根数据通信线:

发送端TXD(Transmit Data)

接收端RXD(Receive Data)

TXD和RXD要交叉连接

3、51单片机串口通信的基本结构

51单片机的串行口主要是由两个独立的串行数据缓存器SUBF(一个发送缓存寄存器,一个接收缓存寄存器)和发送控制器、接收控制器、输入移位寄存器及若干控制门电路组成。串行口的基本结构如图所示:

关于SUBF:串口数据缓存寄存器,物理上是两个独立的寄存器,但是占用相同的地址。写 *** 作时,写入的是发送寄存器;读 *** 作时,读出的是接收寄存器。

①:接收端:数据通过RXD接收引脚,再通过移位寄存器将数据转存到接收寄存器中

②:发送端:讲数据从发送寄存器中移出,通过TXD发送引脚将数据发送出去

③:波特率:通过设置定时器1的初值,获取T1溢出率,通过SMOD模式的设置求取波特率

④:中断:通过发送中断标志位或接收中断标志位是否被置位,判断是否进入串口中断程序,在接收数据完成后,会将RI置位,产生一个接收中断;在发送完成后,会将TI置位,产生发送中断

4、传播速率——比特率

比特率是指每秒传送的比特(bit)数。单位为bps(bit per second)也可表示为b/s,比特率越高,单位时间传送的数据量(位数)越大。

5、波特率

在串口通信中,收发双方对发送或接收数据的速率有约定,即双方要有相同的波特率,我们可以通过编程对单片机串行口设定4中工作方式:

其中,T1的溢出率 = 1/T1溢出的时间

①:关于定时器1方式的选择

在说选取定时器1方式之前插一句:这里的定时器1方式2不是串口那4中方式中的方式2;

在学习定时器的相关知识的时候,我们知道定时器有4种不同的工作方式,在串口通信的实验中,我们选择的是定时器1的工作方式2;

定时器T1工作于方式0:溢出所需周期数=8192-x

定时器T1工作于方式1:溢出所需周期数=65536-x

定时器T1工作于方式2:溢出所需周期数=256-x

为什么不选择定时器1的工作方式1:

如果我们使用定时器1的工作方式1在中断中装初值的方法来T1溢出率的话,在进入中断、重装值、出中断这个过程中很容易产生时间上的微小的误差,当多次 *** 作时微小的误差不断累积,终会产生错误;

为什么选择定时器1的工作方式2:

因为方式2为自动重装初值的8位定时器/计数器模式(自动重装载就是在定时器溢出后自动装入设定的初值,这样的好处当然是显而易见的,不需要在中断服务器里手动赋值了,所以可以精确的定时)所以用它来做波特率发生器最恰当。

②:波特率的计算

在上面介绍串口四种方式的时候提到了波特率的计算公式,由公式可以看出,串口方式0和方式2的波特率是固定的;方式1和方式3的波特率是可变的(根据定时器T1的溢出率来控制)

话不多说,根据题来理解:

根据已知波特率,如何计算定时器1方式2下计数寄存器中的初值:

已经波特率 = 9600,系统的晶振频率 = 12Mhz,求给TH1和TL1的初值:

由此可见,当系统的晶振频率为12Mhz时,定时器的初值不是整数;经过计算可得,当晶振频率为110592Mhz时,(256-x) = 3;

当时钟频率选用110592MHZ时,取易获得标准的波特率,所以很多单片机系统选用这个看起来“怪”的晶振就是这个道理。

6、波特率与比特率关系与区别

码元:在数字通信中常常用时间间隔相同的符号来表示一个 二进制数字 ,这样的时间间隔内的信号称为 (二进制)码元。

在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。即波特率是指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示。每秒钟通过信道传输的信息量称为位传输速率,简称比特率。比特率表示有效数据的传输速率。波特率与比特率的关系是比特率=波特率X单个调制状态对应的二进制位数。波特率是传输通道频宽的指标。

二、串口通信有关寄存器

1、数据缓存寄存器

SBUF是可以直接寻址的专用寄存器。物理上,它对应着两个寄存器,即一个发送寄存器一个接收寄存器,CPU写SBUF就是修改发送寄存器;读SBUF就是读接收寄存器。接收器是双缓冲的,以避免在接收下一帧数据之前,CPU未能及时的响应接收器的中断,没有把上一帧的数据读走而产生两帧数据重叠的问题。对于发送器,为了保持最大的传输速率,一般不需要双缓冲,因为发送时CPU是主动的,不会产生重叠问题。

2、电源寄存器PCON

该寄存器是用来管理单片机的电源部分,包括上电复位检测,掉电模式,空闲模式等

在串口通信中,我们仅仅需要关注SMOD这一位

SMOD = 0且串口方式为1、2、3时,波特率正常

SMOD = 1且串口方式为1、2、3时,波特率加倍

3、状态寄存器SCON(98H)

SM0 SM1:工作方式选择位,串行口有四种工作方式,他们由SM0和SM1设定,其对应关系表如下:

SM2:多机通信时的接收允许标志位

REN:允许串行接收位

TB8,RB8:发送接收数据的第9位,当串口工作于方式2或3 时使用到,指向的是串行传输的第9位数据;

1)SM2=0,在方式2或3下,TB8、RB8 发送与接收第9位奇偶校验位;

2)SM2=1,多机通信时的接收允许位,并且在方式2或3下工作;

TI:发送中断标志位,在方式0时,当串行发送第8位数据结束时,或在其他方式,串行发送停止位的开始时,由其内部硬件使TI置1,向CPU发出中断申请。在中断服务程序中,必须用软件将其清 0,取消此中断申请。

RI:接收中断标志位,在方式0时,当串行接收第8位数据结束时,或在其他方式,串行接收停止位的中间时,由内部硬件使RI置1,向CPU发出中断申请。也必须在中断服务程序中,用软件将其清0,取消此中断申请。

三、串口通信代码

串行口在工作之前,应对其进行初始化,主要是设置产生波特率的定时器1,串行口控制和中断控制。

void usart_init()

{

TMOD = 0x20; //选择定时器1的工作方式2

TH1 = 0xF3; //通过设置定时器1的初值来选择波特率

TL1 = 0xf3;

TR1 = 1; //打开计数器

SCON = 0x50; //0101 0000

PCON = 0x80;

ES = 1; //打开通信中断 ①

EA = 1; //打开总中断 ②

}

或者

void usart_init()

{

TMOD = 0x20;

TH1 = 253;

TL1 = 253;

TR1 = 1;

SM0 = 0;

SM1 = 1;

// REN = 1

// EA = 1;

// ES = 1;

}

在编写串口发送端程序时,无需用到接收数据和中断服务函数,所以REN、EA、ES不需要对他们进行 *** 作

1、NetAssist 支持16进制的发送与16进制接收显示

2、NetAssist软件支持hex发送与定时发送

3、NetAssist网络调试助手支持UDP,TCP协议,支持单播/广播,集成TCP服务器与客户端

4、NetAssist支持ASCII/Hex发送,发送与接收的数据可以在16进制与AscII码之间任何转换

5、可以自动发送校验位,支持多种校验格式

6、NetAssist网络调试助手支持间隔发送,循环发送,批处理发送,输入数据可以从外部文件导入

NetAssist 使用说明:

1、可以以类似与串口助手的方式工作,连接远程机器的端口或自己开端口让其他机器连接,而后有两个窗口,一个显示接收的数据,一个显示发送的数据,可以以ASCII码与十六进制显示

2、NetAssist网络调试助手TCP通信端口号问题A---TCP Server

3、B---TCP Client

4、端口都设置为8080

5、A发到B的数据,显示receive from IP(A):8080

6、B发到A的数据,显示receive from IP(B):端口多变,不是8080

以上就是关于Linux C语言 C/S程序,客户端发送的数据和服务器端接收到的数据不一样,求解全部的内容,包括:Linux C语言 C/S程序,客户端发送的数据和服务器端接收到的数据不一样,求解、c#通过程序如何通过网口发送和接受数据、将数据库里的大量数据通过TCP/IP协议发送到服务器端,用VC++套接字编程应该是 怎样的思路求指教!!等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10220009.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存