C语言 udp通信

// serv.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <STDIO.H>    
#include <STDLIB.H>    
#include <WINSOCK.H>    
#pragma comment (lib, "ws2_32.lib")

#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"Winmm.lib")

void ReiveData();
HANDLE hThreadHandle_page1;
DWORD  dwThreadID_page1;
int fromlen;
int sendlen;
SOCKET socket1;
SOCKET socket2;
struct sockaddr_in client1;   
struct sockaddr_in client2;


/*
仿真机与DCS双向发送的数据包格式相同,都由16字节的头部和最长1200字节的数据区构成。以下定义各字段字节数均按32位平台计算。
头部定义如下:
域号,unsigned char,仿真机向DPU发送数据时,是目标站的域号。如果目标站是全部DPU,填0xFF。当DPU向仿真机发送数据时,是源站(DPU)的域号。
站号,unsigned char,仿真机向DPU发送数据时,是目标站的站号。如果目标站是全部DPU,填0xFF。当DPU向仿真机发送数据时,是源站(DPU)的站号。
字节序标志,unsigned char,对于X86平台,等于1。
包类型,unsigned char,实时数据=128,命令=129,命令回应=130。
秒,unsigned long,代表数据发送时刻的数值(C函数time()的返回值)。
毫秒,unsigned short,数据发送时刻的毫秒部分。
CRC,unsigned short,数据区的CRC16校验值。
数据区长度,unsigned short,数据区的实际字节数(不含头部)。
数据包流水号,unsigned short,为过滤重复数据包,每包可给定不同的数字。
其中时间、CRC和数据包流水号可选。暂时可不处理这几项数据。
数据区是模拟量或开关量的实时数据,每个点占用8字节,两种数据可混合排放。每个点定义如下:
点ID,unsigned int,对照表规定了每个点的ID。
数值,float/int,由点ID确定点记录后,根据类型(模拟/开关)把数值部分的4字节解释为浮点数或整数。如果是开关点,整数是0或1。
根据以上定义,每个数据包最多容纳150个点记录的数据。
*/
typedef struct {    
    unsigned int ID;
    char simbuff[4];
   } DATAFIELD;
typedef struct
{
    unsigned char domainname;  //1byte 1
    unsigned char stationid;   //1byte 2
    unsigned char byteflag;    //1byte 3
    unsigned char datatype;    //1byte 4  
    unsigned long second;      //4byte 8
    unsigned short milsecond;  //2byte 10
    unsigned short CRC16;      //2byte 12
    unsigned short databyte;   //2byte 14
    unsigned short datanum;   // 2byte 16  共16字节
    DATAFIELD data[150];
}SIMDATA;
typedef struct
{
    unsigned char domainname;
    unsigned char stationid;
    unsigned char byteflag;
    unsigned char datatype;
    unsigned long second;
    unsigned short milsecond;  
    unsigned short CRC16;
    unsigned short databyte;
    unsigned short datanum;
    int cmd;  //命令
    unsigned int  parm1 ;//参数1
    long parm2; //参数2
}CMDDATA;
/*
命令和参数定义如下:
命令    含义    参数1    参数2
1    运行/冻结    1运行,0冻结    忽略
2    抽点/回退    1回退,0抽点    组号
3    初始条件保存和加载    1保存条件,0加载条件     组号
4    抽点文件保存和加载    1保存,0加载    组号
5    删除所有抽点文件    忽略    忽略
6    删除所有初始条件    忽略    忽略
7    按参数判断删除那种文件
    0:删除初始文件

1:删除抽点文件    仅当参数1等于0有效
-1:删除所有的初始文件
大于等于0的数字:要删除的初始文件组号。
*/

typedef struct
{
    unsigned char domainname;  
    unsigned char stationid;
    unsigned char byteflag;
    unsigned char datatype;
    unsigned long second;
    unsigned short milsecond;  
    unsigned short CRC16;
    unsigned short databyte;
    unsigned short datanum;
    int cmd ;
    int error;
}CMDDATA_DCS;
/*
数值    含义
0    成功
1    指令或参数无效
2    指定文件不存在
3    访问指定文件出错(无访问权限,文件内容错误等)
*/
//SIMDATA simdata;
//CMDDATA_DCS simcmd;


int    o_num ;
int i_num ;
int ao_num ;
int do_num ;
int    di_num ;
int    ai_num ;
#define REAL    1
#define FLOAT   2
#define LONG    3
#define SHORT   4
#define INT     5
#define LOG     6
#define DOUBLE  7
#define DOUBLE2  8
#define S3_VARLEN   48
typedef union {    
    double  r8;
    float   r4;
    int     i4;
     double i8;
    short   i2;
    char    i1;
   } VAL;/*from s3_parm.h variable value*/
typedef char VAR[S3_VARLEN] ; /*variable name*/
typedef struct
{
    VAR varname;
    int index;
    char *vaddress;
    VAL  oldvarvalue;
    char type1; //r,i,
    char type2; //r,i,
    char vartype;
}DATA;
typedef struct
{
    int index; /* the order of variable in the picture*/
    char vartype;
  VAL varvalue;
}getdata;
#define AO 1
#define DO 2
#define AI 3
#define DI 4
#define pr
#define MAXIN 10240
#define MAXOUT 20480//10240
#define INLEN 16*MAXIN+8
#define OUTLEN 16*MAXOUT+8
DATA data_i[MAXIN];
DATA data_o[MAXOUT];
getdata val_i[MAXIN];
getdata val_o[MAXOUT];
float fgsevalue[MAXOUT];
int igsevalue[MAXOUT];
//

float global_floatdata[100];
float sim_data[150];
unsigned char simbuff[1216];
char m_buffer[1216];
char send_buffer[28];
char simbuff_cmd[28];
char cmd_buffer[28];
int all_data_count;
int count150;
SIMDATA simdata;
CMDDATA simcmd;

#define DATA_RECEIVE_LEN 1216    //数据包
char rev_buffer[DATA_RECEIVE_LEN];
unsigned char rev_data[DATA_RECEIVE_LEN];
unsigned char revbuff[DATA_RECEIVE_LEN];
float global_revdata[100];
int cmd;
unsigned int parm1;
long parm2;
SIMDATA revdata;
CMDDATA_DCS revcmd;


int InitSocket(); //初始化套接字
void SendParametorDataByTimer( ); //发送参数信息,以一定时间间隔,如0.1秒或1秒等
void SendCommandDataChange( );  //发送命令信息,当命令字发生变化
void buildData_Head(); //建立数据头数据
void buildData_CMDHead(); //建立命令头数据
void GetRealValue(); //获取实时值
void ReceiveCommandDataChange( );  //接收DCS命令信息,当命令字发生变化
void buildData_Head() //建立数据头数据
{
    simdata.domainname = 0xFF;
    simdata.stationid = 0xFF;
    simdata.byteflag = 1;
    simdata.datatype = 128;
    simdata.second = 128;
    simdata.milsecond = 1;
    simdata.CRC16 = 0;
    simdata.databyte =1200;
    simdata.datanum = 0;
 }


void buildData_CMDHead() //建立命令头数据
{
    simcmd.domainname = 0xFF;
    simcmd.stationid = 0xFF;
    simcmd.byteflag = 1;
    simcmd.datatype = 129;
    simcmd.second = 128;
    simcmd.milsecond = 1;
    simcmd.CRC16 = 0;
    simcmd.databyte =12;
    simcmd.datanum = 0;
 }
/************************************************************************************************************
             GetAddrFromDBM
*************************************************************************************************************/

void GetRealValue() //获取实时值
{   
    
      int ista,i,j;  

   // for( i=0;i<ao_num+do_num;i++)
      for( i=0;i<all_data_count;i++)
    {   
       //memcpy(&fgsevalue[i],data_o[i].vaddress+4*i,4);
       fgsevalue[i] = i*10.;
       //printf("fgsevalue %f i= %d  \n", fgsevalue[i], i );
    }   
          printf("finished get real time value.\n");
}
void ReiveData()
{
    int i;
    float gsedata[150];

    while (1)   
    {     
        printf("waiting for message from others-------------\n");   
        if (recvfrom(socket1,rev_buffer,sizeof(rev_buffer),0,(struct sockaddr*)&client1,&sendlen)!=SOCKET_ERROR)   
        {   
             memcpy(&revbuff,rev_buffer,sizeof(rev_buffer));

             memcpy(&revdata.domainname, &revbuff[0], sizeof(char));
             memcpy(&revdata.stationid,  &revbuff[1], sizeof(char));
             memcpy(&revdata.byteflag,   &revbuff[2], sizeof(char));
             memcpy(&revdata.datatype,   &revbuff[3], sizeof(char));
             memcpy(&revdata.second,     &revbuff[4], 4*sizeof(char));
             memcpy(&revdata.milsecond,  &revbuff[8], 2*sizeof(char));
             memcpy(&revdata.CRC16,      &revbuff[10], 2*sizeof(char));
             memcpy(&revdata.databyte,   &revbuff[12], 2*sizeof(char));
             memcpy(&revdata.datanum,    &revbuff[14], 2*sizeof(char));

             printf("%d  simdata.databyte \n",revdata.databyte);

             int value = revdata.databyte;
      if(value == 1200){
             memcpy(&revdata.data,   &revbuff[16], 1200*sizeof(char));
             for (i = 0;i<150;i++)
             {
                 memcpy( &gsedata[i] ,&revdata.data[i].simbuff, 4*sizeof(char) );
                // printf( "gsedata i = %d  value = %f \n",i, gsedata[i]);
             }
           //  printf("%x  revdata.domainname \n",revdata.domainname);
            // printf("%x  revdata.stationid \n",revdata.stationid);
            // printf("%x  revdata.byteflag \n",revdata.byteflag);
            // printf("%x  revdata.datatype \n",revdata.datatype);
            //  printf("%d  revdata.second \n",revdata.second);
              printf("%d  simdata.databyte \n",revdata.databyte);
              printf("%d  simdata.datanum \n",revdata.datanum);

              printf("--------------------------------\n");
             // printf("revdata.data.ID %d \n",revdata.data[0].ID);

             // printf("revdata.data.simbuff %f \n",revdata.data[0].simbuff);

             // printf("revdata.data.ID %d \n",revdata.data[2].ID);
           //   printf("revdata.data.simbuff %f \n",revdata.data[2].simbuff);
      }
      else if ( value == 12){
              memcpy(&cmd,   &revbuff[16], 4*sizeof(char));
              memcpy(&parm1,   &revbuff[20], 4*sizeof(char));
              memcpy(&parm2,   &revbuff[24], 4*sizeof(char));
              printf("cmd ****** %d \n",cmd);
              printf("parm1 ****** %d \n",parm1);
              printf("parm2 ****** %d \n",parm2);
      }
        }   
           
    }   
    closesocket(socket1);       
}
void SendParametorDataByTimer( )  //发送参数信息,以一定时间间隔,如0.1秒或1秒等
{   int i,j;
    bool m_nThreadStatus = true;
    memset(m_buffer, 0, sizeof(m_buffer));
    all_data_count = 1500;

    //while( m_nThreadStatus )
    {

         GetRealValue(); //获取实时运行数据
/***************************仿真数据包********************/
         buildData_Head();//封装数据包头

         //all_data_count = ao_num+do_num;
        //仿真数据
        if( all_data_count< 150)
        {
             for (i=0;i<all_data_count;i++)
             {
                simdata.data[i].ID = data_o[i].index;
                sim_data[i] = fgsevalue[i];
                memcpy( simdata.data[i].simbuff,&sim_data[i],4*sizeof(char));
                
             }
             for (i=all_data_count;i<150;i++) //填充无用数据
             {
                simdata.data[i].ID = 200000;
                sim_data[i] = 0;
                memcpy( simdata.data[i].simbuff,&sim_data[i],4*sizeof(char));
                
             }
          memcpy(simbuff, &simdata, sizeof(SIMDATA));
          memcpy(m_buffer,simbuff,sizeof(simbuff));
         if( sendto(socket1,m_buffer,sizeof(m_buffer),0,(struct sockaddr*)&client2,sendlen)!=SOCKET_ERROR)
         {  
            printf("sending data successly ..\n");
         }
        }
          //>150或者为其整数倍
            count150 = (int)(all_data_count/150.);
            for(j = 0;j< count150;j++)
           {
               simdata.datanum = j+1;
             for (i=0;i<150;i++)
             {
                simdata.data[i].ID = data_o[i+j*150].index;
                sim_data[i] = fgsevalue[i+j*150];
                memcpy( simdata.data[i].simbuff,&sim_data[i],4*sizeof(char));
                
             }
                simcmd.datanum = j+1;
                memcpy(simbuff, &simdata, sizeof(SIMDATA));
                memcpy(m_buffer,simbuff,sizeof(simbuff));
                if( sendto(socket1,m_buffer,sizeof(m_buffer),0,(struct sockaddr*)&client2,sendlen)!=SOCKET_ERROR)
               {  
                   printf("sending data successly ..\n");
                 }
            }
            
         //Sleep(1000);                
    }
     //closesocket (socket2);
    
}
void SendCommandDataChange( )  //发送命令信息,当命令字发生变化
{
    int i;
    bool m_nThreadStatus = true;
    //memset(cmd_buffer, 0, sizeof(cmd_buffer));
    //while( m_nThreadStatus )
    {

        /*命令数据包*/
         buildData_CMDHead();
         simcmd.cmd = 1;
         simcmd.parm1 = 1;
         simcmd.parm2 = 0;
         if(simcmd.datanum == 0 )
             simcmd.datanum = 1;
         else
             simcmd.datanum = 0;
        memcpy(simbuff_cmd, &simcmd, sizeof(CMDDATA));
      
        memcpy(cmd_buffer,simbuff_cmd,sizeof(simbuff_cmd));
        if( sendto(socket2,cmd_buffer,sizeof(cmd_buffer),0,(struct sockaddr*)&client2,sendlen)!=SOCKET_ERROR)
        {  
            printf("sending data successly ..\n");
         }

        //Sleep(1000);    
     }
      //closesocket (socket2);
}

// add by ch

const int MAX_KEY_NUM = 128;
const int MAX_KEY_LENGTH = 1024;

char gKeys[MAX_KEY_NUM][MAX_KEY_LENGTH];

char *GetIniKeyString(char *title, char *key, char *filename)
{
    FILE *fp;
    int  flag = 0;
    char sTitle[32], *wTmp;
    char sLine[MAX_KEY_LENGTH];

    sprintf(sTitle, "[%s]", title);
    if (NULL == (fp = fopen(filename, "r")))
    {
        perror("fopen");
        return NULL;
    }

    while (NULL != fgets(sLine, MAX_KEY_LENGTH, fp))
    {
        /// 这是注释行  ///
        if (0 == strncmp("//", sLine, 2)) continue;
        if ('#' == sLine[0])              continue;

        wTmp = strchr(sLine, '=');
        if ((NULL != wTmp) && (1 == flag))
        {
            if (0 == strncmp(key, sLine, wTmp - sLine))  /// 长度依文件读取的为准  ///
            {
                sLine[strlen(sLine) - 1] = '\0';
                fclose(fp);
                return wTmp + 1;
            }
        }
        else
        {
            if (0 == strncmp(sTitle, sLine, strlen(sLine) - 1))  /// 长度依文件读取的为准  ///
            {
                flag = 1; /// 找到标题位置  ///
            }
        }
    }
    fclose(fp);
    return NULL;
}

void WINAPI onTimeCommand(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2);  

void WINAPI onTimeCommand(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2)  
{  
    printf("onTimeCommand do ...\n");  
    SendCommandDataChange();
    return;  
}

void WINAPI onTimePara(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2);  

void WINAPI onTimePara(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2)  
{  
    printf("onTimePara do ...\n");  
    SendParametorDataByTimer();
    return;  
}

//开启2个定时器
void startTimer()
{

    char * timeCommand =  (char*)malloc(100 * sizeof(char));
    strcpy(timeCommand,GetIniKeyString("Timer", "timeCommand", "config.ini"));    
    printf("timeCommand is %s\n", timeCommand);

    MMRESULT timer_command;  
    timer_command = timeSetEvent(atoi(timeCommand), 1, (LPTIMECALLBACK)onTimeCommand, DWORD(1), TIME_PERIODIC);   

     if(NULL == timer_command)  
    {  
        printf("timeSetEvent()timer_command  failed with error %d/n", GetLastError());  
        return ;  
    }


     char * timePara =  (char*)malloc(100 * sizeof(char));
    strcpy(timePara,GetIniKeyString("Timer", "timePara", "config.ini"));    
    printf("timePara is %s\n", timePara);

     MMRESULT timer_para;  
    timer_para = timeSetEvent(atoi(timePara), 1, (LPTIMECALLBACK)onTimePara, DWORD(1), TIME_PERIODIC);   

     if(NULL == timer_para)  
    {  
        printf("timeSetEvent() timer_para failed with error %d/n", GetLastError());  
        return ;  
    }

}

// add by ch

int _tmain(int argc, _TCHAR* argv[])
{

    WSADATA wsaData;   

    if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL    
    {    
        printf("Winsock无法初始化!\n");   
        WSACleanup();   
        return 0;   
    }   
       
    printf("服务器开始创建SOCKET。\n");   
 

    //读取配置文件开始

    char * ipOne =  (char*)malloc(100 * sizeof(char));
    strcpy(ipOne,GetIniKeyString("IPSite", "socketOneIp", "config.ini"));    
    printf("ipOne is %s\n", ipOne);

    char * portOne  =  (char*)malloc(100 * sizeof(char));
    strcpy(portOne,GetIniKeyString("IPSite", "socketOnePort", "config.ini"));
    printf("portOne is %s\n", portOne);

    char * ipTwo  =  (char*)malloc(100 * sizeof(char));
    strcpy(ipTwo,GetIniKeyString("IPSite", "socketTwoIp", "config.ini"));
    printf("ipTwo is %s\n", ipTwo);

    char * portTwo  =  (char*)malloc(100 * sizeof(char));
    strcpy(portTwo,GetIniKeyString("IPSite", "socketTwoPort", "config.ini"));
    printf("portTwo is %s\n", portTwo);

    //读取配置文件结束


     fromlen =sizeof(client1);   
    client1.sin_family=AF_INET;   
    client1.sin_port=htons(atoi(portOne)); ///监听端口      
    client1.sin_addr.s_addr=inet_addr(ipOne); ///server的地址
    
    socket1=socket(AF_INET,SOCK_DGRAM,0);   
    bind(socket1,(struct sockaddr*)&client1,sizeof(client1));

    sendlen =sizeof(client2);   
    client2.sin_family=AF_INET;   
    client2.sin_port=htons(atoi(portTwo)); ///监听端口      
    client2.sin_addr.s_addr=inet_addr(ipTwo); ///server的地址
    
    socket2=socket(AF_INET,SOCK_DGRAM,0);   
    //bind(socket2,(struct sockaddr*)&client2,sizeof(client2));

    startTimer(); // add by ch

   // ReiveData();
    SendParametorDataByTimer( );
    //SendCommandDataChange( );
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Linux虚拟机上实现C语言UDP通信,你需要遵循以下步骤: 1. 安装必要的软件包:在Linux虚拟机上安装必要的软件包,包括gcc、g++、make和libc-dev。 2. 编写UDP服务器代码:使用C语言编写UDP服务器代码并保存为server.c。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 #define BUFFER_SIZE 1024 int main() { int sockfd; struct sockaddr_in server_addr, client_addr; char buffer[BUFFER_SIZE]; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } memset(&server_addr, 0, sizeof(server_addr)); memset(&client_addr, 0, sizeof(client_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); if (bind(sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } int len, n; len = sizeof(client_addr); n = recvfrom(sockfd, (char*)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&client_addr, &len); buffer[n] = '\0'; printf("Client : %s\n", buffer); sendto(sockfd, (const char*)buffer, strlen(buffer), MSG_CONFIRM, (const struct sockaddr*)&client_addr, len); printf("Message sent to the client.\n"); return 0; } ``` 3. 编译UDP服务器代码:使用以下命令将server.c编译为可执行文件server。 ``` gcc server.c -o server ``` 4. 编写UDP客户端代码:使用C语言编写UDP客户端代码并保存为client.c。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 #define BUFFER_SIZE 1024 int main() { int sockfd; struct sockaddr_in server_addr; char buffer[BUFFER_SIZE]; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = INADDR_ANY; int n, len; printf("Enter message to send : "); fgets(buffer, BUFFER_SIZE, stdin); sendto(sockfd, (const char*)buffer, strlen(buffer), MSG_CONFIRM, (const struct sockaddr*)&server_addr, sizeof(server_addr)); printf("Message sent to the server.\n"); n = recvfrom(sockfd, (char*)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr*)&server_addr, &len); buffer[n] = '\0'; printf("Server : %s\n", buffer); close(sockfd); return 0; } ``` 5. 编译UDP客户端代码:使用以下命令将client.c编译为可执行文件client。 ``` gcc client.c -o client ``` 6. 运行代码:在虚拟机上运行UDP服务器代码和UDP客户端代码。首先,运行UDP服务器。 ``` ./server ``` 然后在另一个终端中运行UDP客户端。 ``` ./client ``` 输入要发送的消息,然后等待服务器的响应。 这样,你就可以在Linux虚拟机上使用C语言实现UDP通信了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值