基于HHARM9-EDU的TCP/IP(UDP)协议的实现

基于HHARM9-EDU的TCP/IP(UDP)协议的实现
 
嵌入式技术的发展日新月异,现如今,嵌入式设备已经广泛应用于各种网络,本文简要地说明一下如何实现PC与HHARM9-EDU之间的TCP/IP(UDP) 通讯。
 
 
① 回顾一下什么是TCP/IP协议:
传统的开放式系统互连参考模型,是一种通信协议的7层抽象的参考模型,其中每一层执行某一特定任务。该模型的目的是使各种硬件在相同的层次上相互通信。这7层是:物理层、数据链路层、网路层、传输层、话路层、表示层和应用层。
TCP/IP起源于美国国防部高级研究规划署(DARPA)的一项研究计划——实现若干台主机的相互通信。现在TCP/IP已成为Internet上通信的工业标准。
TCP/IP通讯协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。这4层分别为:
应用层:应用程序间沟通的层,如简单电子邮件传输(SMTP)、文件传输协议(FTP)、网络远程访问协议(Telnet)等。
传输层:在此层中,它提供了节点间的数据传送服务,如传输控制协议(TCP)、用户数据报协议(UDP)等,TCP和UDP给数据包加入传输数据并把它传输到下一层中,这一层负责传送数据,并且确定数据已被送达并接收。
网络层:负责提供基本的数据封包传送功能,让每一块数据包都能够到达目的主机(但不检查是否被正确接收),如网际协议(IP)。
网络接口:对实际的网络媒体的管理,定义如何使用实际网络(如Ethernet、Serial Line等)来传送数据。
TCP/IP与OSI参考模型的对应关系如下:
 
 
② 网络传输中另一个重要概念――端口:
按照 OSI七层模型的描述,传输层提供进程(应用程序)通信的能力。为了标识通信实体中进行通信的进程(应用程序),TCP/IP协议提出了协议端口(protocol port,简称端口)的概念。
端口是一种抽象的软件结构(包括一些数据结构和 I/O缓冲区)。应用程序通过系统调用与某端口建立连接(binding)后,传输层传给该端口的数据都被相应的进程所接收,相应进程发给传输层的数据都通过该端口输出。
端口用一个整数型标识符来表示,即端口号。端口号跟协议相关, TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立。
端口使用一个 16位的数字来表示,它的范围是0~65535,1024以下的端口号保留给预定义的服务。例如:http使用80端口。
 
 
③ 套接字(socket)的引入:
为了能够方便的开发网络应用软件,由美国伯克利大学在 Unix上推出了一种应用程序访问通信协议的操作系统调用socket(套接字)。socket的出现,使程序员可以很方便地访问TCP/IP,从而开发各种网络应用的程序。
随着 Unix的应用推广,套接字在编写网络软件中得到了极大的普及。后来,套接字又被引进了Windows等操作系统,成为开发网络应用程序的非常有效快捷的工具。
套接字存在于通信区域中。通信区域也叫地址族,它是一个抽象的概念,主要用于将通过套接字通信的进程的共有特性综合在一起。套接字通常只与同一区域的套接字交换数据(也有可能跨区域通信,但这只在执行了某种转换进程后才能实现)。 Windows Sockets只支持一个通信区域:网际域( AF_INET),这个域被使用网际协议簇通信的进程使用。
 
 
④ 什么是UDP协议:
UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端, UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
基于 UDP(面向无连接)的socket编程:
⑴服务器端(接收端)程序:
1、创建套接字( socket)。   
2、将套接字绑定到一个本地地址和端口上( bind)。
3、等待接收数据( recvfrom)。
4、关闭套接字。
 
⑵客户端(发送端)程序:
1、创建套接字( socket)。   
2、向服务器发送数据( sendto)。
3、关闭套接字。
 
 
⑤ 具体编程实现如下:
一共有两个程序:服务器端(接收端)程序和客户器端(发送端)程序
服务器端程序运行在实验箱上,客户端程序运行在 PC上,从客户端发送消息,服务端收到消息显示在触摸屏上,并回复一条消息给客户端。
下面分别说明:
⑴服务器端(接收端)程序:
服务器端程序运行在实验箱上。
首先在 PC上调试,操作系统是RedHat 9,调试工具为MINIGUI V1.3.3,MINIGUI上调试完成后,交叉编译后在实验箱上成功运行,效果图如下:
 
附:源代码
#include <minigui/dti.c>
#include <stdio.h>         
#include <strings.h>         
#include <unistd.h>        
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include <minigui/mywindows.h>
#include <minigui/mgext.h>
 
#define IDC_static                100
#define IDC_listbox                200
#define IDC_edit                 300
#define IDC_send                400
#define PORT 1234   /* 端口号 */
#define MAXDATASIZE 100    /* 最大字节数 */
    char tempBuf[200];
int sockfd; /* socket 描述符 */
    struct sockaddr_in server; /* 服务端地址信息 */
    struct sockaddr_in client; /* 客户端地址信息 */
    int sin_size;
    int num;
    char msg[MAXDATASIZE]; 
    initserver(HWND hDlg)
    {
    /* 建立 UDP socket */
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
    perror("Creating socket failed.");
    exit(1);
    }
 
    bzero(&server,sizeof(server)); 
    server.sin_family=AF_INET;
    server.sin_port=htons(PORT);
    server.sin_addr.s_addr = htonl (INADDR_ANY);
    if (bind(sockfd, (struct sockaddr *)&server,
        sizeof(struct sockaddr)) == -1)
    {
    perror("Bind error.");
    exit(1);
    }       
    }
   
CTRLDATA CtrlTest[]=
{
        {
                "static",
                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| WS_EX_TRANSPARENT,
                0, 50, 240, 200,
                IDC_static,
                "message",
                0
        },
        {
                "listbox",
                WS_CHILD | WS_VISIBLE | WS_VSCROLL,
                0, 0, 240, 45,
                IDC_listbox,
                "ip",
                0
        },
        {
                "edit",
                WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| WS_EX_TRANSPARENT,
                5, 255, 160, 25,
                IDC_edit,
                "",
                0
        },
        {
                "button",
                WS_CHILD | WS_VISIBLE,
                175, 255, 50, 25,
                IDC_send,
                "send",
                0
        },
};
 
DLGTEMPLATE DlgTest =
{
        WS_VISIBLE | WS_CAPTION | WS_BORDER| WS_EX_TRANSPARENT,
        WS_EX_NONE,
        0, 0, 240, 320,
        "UDP Test",
        0, 0,
        4, CtrlTest,
        0
};
 
/************************************************************************/
static int TestWinProc(HWND hDlg, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        case MSG_INITDIALOG:
        initserver(hDlg);
        SetTimer(hDlg,1,10);
        break;
    case MSG_TIMER:
        sin_size=sizeof(struct sockaddr_in);
        num = recvfrom(sockfd,msg,MAXDATASIZE,0,
            (struct sockaddr *)&client,&sin_size);                                   
 
        if (num < 0){
        perror("recvfrom error/n");
        exit(1);
        }
 
        msg[num] = '/0';
        printf("You got a message (%s) from %s/n",
            msg,inet_ntoa(client.sin_addr) );
        SetWindowText (GetDlgItem (hDlg, IDC_static), msg);
        sprintf(tempBuf,"Welcome %s to my server.",
            inet_ntoa(client.sin_addr));
        sendto(sockfd,tempBuf,strlen(tempBuf)+1,0,
            (struct sockaddr *)&client,sin_size);
        if (!strcmp(msg,"quit")) break;
        break;
        case MSG_COMMAND:
           switch(wParam) {
        case IDC_send:
          break;
    }
        break;
 
    case MSG_CLOSE:
        {
        EndDialog (hDlg, 0);
        }
        return 0;
    }
 
     return DefaultDialogProc (hDlg, message, wParam, lParam);
}
 
/************************************************************************/
 
int MiniGUIMain (int argc, const char* argv[])
{
    DlgTest.controls = CtrlTest;
   
    DialogBoxIndirectParam (&DlgTest, HWND_DESKTOP,
        TestWinProc, 0L);
return 0;
}
 
⑵客户器端(发送端)程序:
客户端程序可以在选择在 Linux下运行,或者在Windows下运行,下面分别说明如何具体实现:
 
㈠Linux下:
我的 Linux系统版本为RedHat 9,在Linux下的开发程序,由于没有像VC之类的强大开发工具,所以编程比较麻烦,调试起来也不方便,Linux下的程序采用存C编写,本程序没有编写图形界面,只开发了一个类似Windows控制台的程序,在功能上实现了PC与实验箱之间的通信,效果图如下:
附:源代码
    #include <stdio.h>
    #include <unistd.h>
    #include <strings.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>      
 
    #define PORT 1234   /*断口号 */
    #define MAXDATASIZE 100  
 
    int main(int argc, char *argv[])
    {
    int fd, numbytes;  
    char buf[MAXDATASIZE]; 
 
    struct hostent *he;      
    struct sockaddr_in server,reply; /* 服务器地址信息 */
 
    if (argc !=3)
    { 
    printf("Usage: %s <IP Address> <message>/n",argv[0]);
    exit(1);
    }
 
    if ((he=gethostbyname(argv[1]))==NULL)
    {
    printf("gethostbyname() error/n");
    exit(1);
    }
 
    if ((fd=socket(AF_INET, SOCK_DGRAM, 0))==-1)
    { 
    printf("socket() error/n");
    exit(1);
    }
 
    bzero(&server,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)he->h_addr);
    sendto(fd, argv[2], strlen(argv[2]),0,
        (struct sockaddr *)&server,sizeof(struct sockaddr));
 
    while (1) {
    int len;
    recvfrom(fd,buf,MAXDATASIZE,0,(struct sockaddr *)&reply,&len);
    printf("Server Message: %s/n",buf);
    break;
    }
close(fd);   
    }
 
 
㈡Windows下:
我的 Windows版本为Windows XP,在Windows下编写程序就方便多了,由于有了VC,一切工作就简单了一下,在这里我写了两个版本的程序:
1、 Windows控制台程序
2、 图形界面程序
下面分别说明:
1、 Windows 控制台程序
本程序采用 VC6编写,Windows下编写网络程序与在Linux下编写不太一样,主要是socket的调用有较大的不同,此外VC6主要采用C++语言,效果图如下:
附:源代码
#include <Winsock2.h>
#include <stdio.h>
 
void main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
   
    wVersionRequested = MAKEWORD( 1, 1 );
   
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        return;
    }
   
 
    if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
        WSACleanup( );
        return;
    }
 
    SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);
 
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.2.120");
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(1234);
 
    char recvBuf[100];
    char sendBuf[100];
    char tempBuf[200];
 
    int len=sizeof(SOCKADDR);
 
    while(1)
    {
        printf("Please input data:/n");
        gets(sendBuf);
        sendto(sockClient,sendBuf,strlen(sendBuf)+1,0,
            (SOCKADDR*)&addrSrv,len);
        recvfrom(sockClient,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len);
        if('q'==recvBuf[0])
        {
            sendto(sockClient,"q",strlen("q")+1,0,
                (SOCKADDR*)&addrSrv,len);
            printf("Chat end!/n");
            break;
        }
        sprintf(tempBuf,"%s say : %s",inet_ntoa(addrSrv.sin_addr),recvBuf);
        printf("%s/n",tempBuf);
 
    }
    closesocket(sockClient);
    WSACleanup();
}
 
 
2、 图形界面程序
本程序采用 VC6编写,VC6提供了强大的图形界面程序编写工具,让我们开发图形界面程序十分方便,效果图如下:
图形界面程序源代码太长,在这里就不写上了。
 
 
 
 
 
 
 
 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值