技术问题之C语言近程型和远程型的区别是什么

Python035

技术问题之C语言近程型和远程型的区别是什么,第1张

近程就是near,远程就是far

主要早期16位cpu上的dos系统,内存地址是20位的,但寄存器是16位的

这样一个16位的指针,也就是near指针,能访问的内存范围只有64K,但20位的内存地址,实际允许定义大于64K的数据,这样,一个指针就实际就有些数据能访问到,而有些数据不能访问到,这实际是很不好控制也很令人费解的事

而far指针,实际用2个寄存器组合来访问数据,就可以访问所有内存范围了,但是由于这个指针每次参与运算,都要重新计算2个寄存器的值,会造成速度上的一些损失

所以near和far指针各有各的优势,都有存在的理由

但在现代,计算机的寄存器已经和地址长度完全一致了,32位系统,地址是32位,寄存器也是32位,64位系统,地址是64位,寄存器也是64位,near和far指针的概念已经不需要了

DOS用一种分段结构来寻址计算机的内存,每一个物理存储位置都有一个可以用段一偏移量方式来访问的相关地址。例如,下面就是一个典型的段式地址: A000:1234 冒号左边的部分代表段地址(A000),冒号右边的部分代表相对于段地址的偏移量。DOS下的每个程序都是按这种方式访问内存的——尽管段一偏移量寻址方法的机理对大多数C程序员来说是隐蔽的。 当你的程序被执行时,一个存放在数据段(DS)寄存器中的数据段地址将被赋给你的程序。这个缺省的数据段地址指向一个64KB的内存空间,这个空间通常就被叫做近程型数据段。在这个近程型数据段空间中,你会找到程序的栈、静态数据和近程堆。近程堆用来为程序启动时所需的全局变量和其它数据元素分配内存,在这个空间中分配的任何数据都被叫做近程型数据。例如,下面的程序在程序启动时从近程堆中分配了32KB的近程型数据: / * Note :Program uses the Medium memory model...* / # include <stdio. h># include <alloc. h># include <string. h># include <stdlib. h># include <dos. h>void main(void) void main(void) { char * near_datanear_data= (char * )malloc((32 * 1024) * sizeof(char)) if (near data= = (char * )NULL) { printf("Whoopsie ! Malloc failed! \n") exit(l) } strcpy (near_data, "This string is going to be. stored in the near heap") printf("Address of near_data : %P\n", ,&near_data) free (near_data) } 在上例中,near_data是一个字符指针,程序分配给它一个32KB的内存块。在缺省情况下,这个32KB的内存块是从近程堆中分配的,并且相应的16位地址将被存放在字符指针near_data中。 现在,你已经知道什么是近程型数据了,但你可能还不大明白什么是远程型数据,很简单,远程型数据就是位于缺省数据段(第一个64KB数据段)以外的数据。下例中的程序从远程型数据区(通常也叫做远程堆)中分配了32KB的空间: / * Note:Program uses the Medium memory model... * / # include <stdio. h># include <alloc. h># include <string. h># include <stdlib. h>#include <dos. h>void main(void) void main(void) { char far * far_datafar_data= (char far * )farmalloc((32 * 1024) * sizeof(char)) if (far data= = (char far*)NULL) { printf ("Whoopsie ! Far malloc failed ! \n") exit (1) } fstrcpy(far data, "This string is going to be stored in the far heap")printf("Address of far_data : %Fp\n",&far_data) farfree (far_data) } 在这个例子中,远程型字符指针被赋予了一个32位地址,该地址对应于远程堆中一块32KB的可用内存。注意,为了明确地从远程堆中分配内存,必须使用一个far指针,因此上例的字符指针定义中加入了远程型修饰符(far)。此外,你还要注意,从远程堆中分配内存的一些函数(fareoreleft(),farmalloe(),farfree())和从近程堆中分配内存的函数是不同的。 远程堆中的可用内存通常比近程堆中的多得多,因为近程堆被限制在64KB之内。如果你在你的计算机上编译并运行前面的两个例子,你会发现第一个例子(从近程堆中分配内存)大约有63KB的可用内存,而第二个例子(从远程堆中分配内存)大约有400KB到600KB(依赖于你的计算机配置)的可用内存。因此,如果你的程序需要大量的内存来存储数据,你就应该使用远程堆而不是近程堆。 不管使用哪一种存储模式(Tiny存储模式除外),你都可以用near和far修饰符以及相应的近程型和远程型函数来明确地从近程堆和远程堆中分配内存。合理地使用近程型和远程型数据,将有助于提高程序的运行效率,减少程序用尽内存的危险。 注意,因为DOS使用的是段地址结构寻址机制,所以近程型和远程型数据的概念是运行DOS的PC机所独有的。其它操作系统,例如UNIX和Wndows NT,使用的是平面地址机制,没有近程型或远程型限制。

求采纳

以人工气候室远程监控系统为例2.1通信接口-----套接字的创建本文所要实现的是对一个小型人工气候室的远程监控,在异地或同一个局域网范围内,可以不必亲临现场就可以观测到人工气候室当前的温度状况和运行中的温度曲线,由于在远端只是需要查询和观察,因此只要处理好现场监控计算机和远端客户机之间的通信和数据传输就可以了。这样不用占用现场计算机的CPU处理时间,从而能节省资源以便做更多的处理现场的工作。和远端服务器的连接可以分为以下几个过程:(1) 服务进程总是先于客户进程启动,服务进程首先创造套接字。(2) 将本地地址绑定到所创建的套接字上以使在网络上标识该套接字。 (3) 将套接字置于监听模式并准备接受连接请求。(4) 客户端创建套接字,调用SOCKET函数,方法同上。(5) 客户向服务器提出连接请求。(6) 当请求到来时,被阻塞服务进程的accept()函数如(3)中所述生成一个新的套接字与客户端建立连接,并向客户端返回接收信号。(7) 一旦客户机的套接字收到来自服务器的接收信号,则表示客户机与服务器的连接已就绪,则可以进行数据传输了。(8) 关闭套接字。一旦任务完成,就必须关掉连接已释放套接字占用的资源。创建连接的服务器端和客户端代码简述如下:服务器端:void CServerView::OnStart ()

{ Started=TRUE;

m_Start.EnableWindow(!Started);

try

{ g_sListen.Create(6802,SOCK_DGRAM,NULL);

g_sListen.Bind(6802,m_IP);//,6802为端口号,m_IP为服务器端IP地址

g_sListen.Listen();

((CServerDoc*)GetDocument())->g_pchatListen=new CChatLsnSock(

(CAnyServerDoc*)GetDocument());

CChatLsnSock* g_pchatListen=((CAnyServerDoc*)GetDocument())->g_pchatListen;

g_pchatListen->Create(9999,SOCK_STREAM);//侦听聊天室连接套接字创建

g_pchatListen->Listen();

GetDlgItem(IDC_RESPONSE)->SetWindowText("开始对客户端服务!");

}

服务端开启后的运行界面如图1所示。

客户端:

void CClientView::OnClientStart()

{m_sockRecv.Create(6801,SOCK_DGRAM,m_ClientIP)//6801为端口号,m_ClientIP为客户端IP<br>m_sockRecv.Bind(6801,m_ClientIP);<br>m_timer1=SetTimer(1,1000,NULL);<br>m_timer2=SetTimer(2,250,NULL);<br>GetLocalTime(&SysTime);<br>m_StartTime=SysTime;<br>m_WavePlay.SetStartTime(SysTime.wYear,SysTime.wMonth,SysTime.wDay,SysTime.wHour,SysTime.wMinute,SysTime.wSecond);//画出曲线初始时间<br>this->m_CurrentSysTime.SetFocus();<br>}

2.2网络中的数据传输与监控实现基于网络的远程控制和测量应用中,一般数据传输采用二进制格式是主丛式,在人工气候室的远程监控系统中,通信双方需要传输的数据流量少,下位机一般是微控制器等嵌入式系统,数据处理能力较慢,通信双方也不必保持紧密联系,因此大多采用UDP协议,基于点对点的方式,双方通信的数据可靠性可以通过定义数据表示格式来保证。另外采用把通过网络传输过来的数据在客户端用曲线的形式重画显示,用了一个本人自做的一个ActiveX控件来显示接收的数据,在数据传输过程中存在的滞后时间很短,可以忽略不计。在设备运行时,服务器端的状态一直保持开启,测温元件把测量到的温度值传入到控制微机,同时通过网络传到远程客户端,远程连接通过输入服务器端的IP地址,输入指定的用户名和密码,就可以连接上,从而就实现了远程监控。建立连接后客户端就可以接收发送过来的温度值且用曲线形式显示出来:void CClientView::OnDataReceive()

{

extern CListBox* pmyListBox;

char szTempRecv[20];

CString szIP(m_IP);//得到服务器端的IP

UINT uPort=6802;//指出端口

int iTempRecv=m_sockRecv.ReceiveFrom(szRecv,10,szIP,uPort,0);

szRecv[iRecv]='\0';

m_szRecv=szTempRecv;

m_listBox.AddString((LPCTSTR)m_szRecv);

int nCount=m_listBox.GetCount();

if (nCount >0)

m_listBox.SetCurSel(nCount-1);

GetLocalTime(&SystemTime);

m_NowTime=SystemTime;

CString strSysTime;

strSysTime.Format(_T("%d-%d-%d %d:%d:%d"),SystemTime.wYear,SystemTime.wMonth,SystemTime.wDay,SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond);

UpdateData(FALSE);

CurABSTime=(m_NowTime-m_StartTime).GetTotalSeconds();

m_WavePlay.SetPoint2(CurABSTime,atoi(m_szRecv));//用自做ActiveX控件画出温度曲线

完成后通过远程登录看到的运行界面