跨语言、跨设备的socket通信(FriendlyArm开发板与Windows 10PC机进行通信)

        第一次尝试用PC机去控制FriendlyArm友善之臂开发板, 以下的成果是本学期嵌入式系统课程的一个课程设计, 希望能帮助大家了解FriendlyArm友善之臂开发板的使用.

注: 下图中我通过PC端的Linux虚拟机, 以ssh命令远程控制ARM开发板, 远程控制ARM开发板的方法在博文最后会有说明.

        一开始对于以跨语言方式完成socket通信有些头疼, 但后来发现不同语言对于socket通信的实现仅仅是实现形式不同, 基本的原理和流程是基本相同的.

        这个课程设计要求我们通过PC机向ARM开发板发送命令, ARM开发板在接收到不同的命令后, 用其两个发绿色光的LED灯分别以00/01/10/11(0-> 灭, 1 -> 亮)方式做出回应. 补充说明一下, 我将命令分为四大种类: 电压、电导率、电流mA、调零mV(只有电导率档才可调电导挡位). 这里实现的是PC发命令至ARM开发板, 故下图所制作的可视化操作界面仅是命令选择的载体, 在此并无其它含义, 大家不必深入思考.

跨语言、跨设备的socket通信(FriendlyArm开发板与Windows 10PC机进行通信)_第1张图片

        两设备的通信采用TCP协议, PC端作为client, ARM开发板端作为server: 另外PC端可自由开启或关闭程序(窗体).

        ARM开发板端的server.c实现了多客户连接进程并发处理这一功能, 这也是很重要的一点.

        下面说一下该课程设计的启动方式.

        1. 开启PC端的热点.

        2. 在ARM开发板端连接PC端的热点, 这里ARM开发板的IP地址为 192.168.137.243.

        3. 在开发板端终端输入 gcc -o server server.c, 之后输入命令 sudo ./server.

        4. 在PC端启动窗体程序, 选择某一命令, 点击发送即可.

        5. 此时ARM开发板的两个LED灯会随着PC端选择命令的不同而展现出不同的亮灭组合.

//Led_control.h
void led_control(int L1, int L2)
{
    //system("echo 43 > /sys/class/gpio/export");
    //system("echo 44 > /sys/class/gpio/export");
    //以上两条语句在第一次运行server时取消注释, 之后变为注释
    if(L1 == 0 && L2 == 0)//D1 D2 灭
    {
        system("echo low > /sys/class/gpio/gpio43/direction");
        system("echo low > /sys/class/gpio/gpio44/direction");

    }
    else if(L1 == 0 && L2 == 1)//D1灭 D2亮
    {
        system("echo low > /sys/class/gpio/gpio43/direction");
        system("echo high > /sys/class/gpio/gpio44/direction");
    }
    else if(L1 == 1 && L2 == 0)//D1亮 D2灭
    {
        system("echo high > /sys/class/gpio/gpio43/direction");
        system("echo low > /sys/class/gpio/gpio44/direction");
    }
    else if(L1 == 1 && L2 == 1)//D1 D2 亮
    {
        system("echo high > /sys/class/gpio/gpio43/direction");
        system("echo high > /sys/class/gpio/gpio44/direction");
    }
}

//运行于ARM开发板上
#include
#include
#include
#include 
#include 
#include 
#include 
#include 
#include  
#include
#include
#include "Led_control.h"
#define SERVPORT 3333
#define BACKLOG 10
int main()
{
    int sockfd,client_fd;
    int sin_size;
    char s[100];
    struct sockaddr_in my_addr;    
    struct sockaddr_in remote_addr; 
    sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立socket --
    my_addr.sin_family=AF_INET;//AF_INET地址族
    my_addr.sin_port=htons(SERVPORT);//设定端口号(host -> networks)
    my_addr.sin_addr.s_addr = INADDR_ANY;//32位IPv4地址
    bzero(&(my_addr.sin_zero),8); //置前8个字节为0
    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) 
     {
  	  perror("bind 出错!");		
	  exit(1);	
     }
    if (listen(sockfd, BACKLOG) == -1) //监听socket连接,设置队列中最多拥有连接个数为10  --
     {	
	  perror("listen 出错!");	
        exit(1);     
     }
    while(1)
     {
	  sin_size = sizeof(struct sockaddr_in);//记录sockaddr_in结构体所占字节数
	  if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1) //accept()缺省是阻塞函数,阻塞到有连接请求为止 --
          {	
	      perror("accept error");		
	      continue;		
	  }
	  printf("收到一个连接来自: %s\n", inet_ntoa(remote_addr.sin_addr));
	  if (!fork()) 
          { 
		if (send(client_fd, "Successfully connected.", 23, 0) == -1) //--		
		    error("send 出错!");
		//receive a piece of message from host
		int nbytes = recv(client_fd, s, 100, 0);
		s[nbytes] = '\0';			
		//show the message that it has just received.
		int i =0;
		while(i < strlen(s))
		{
			putchar(s[i++]);
		}
		printf("\n");
		if(strcmp(s, "gear1") == 0)
		{
			//command 'gear1'
			//D1 off, D2 off
			puts("function gear1\n");
			led_control(0, 0);
		}
		else if(strcmp(s, "gear2_1") == 0)
		{
			//command 'gear2_1'
			//D1 off, D2 on
			puts("function gear2_1\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_2") == 0)
		{
			//command 'gear2_2'
			//D1 off, D2 on
			puts("function gear2_2\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_3") == 0)
		{
			//command 'gear2_3'
			//D1 off, D2 on
			puts("function gear2_3\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_4") == 0)
		{
			//command 'gear2_4'
			//D1 off, D2 on
			puts("function gear2_4\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_5") == 0)
		{
			//command 'gear2_5'
			//D1 off, D2 on
			puts("function gear2_5\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_6") == 0)
		{
			//command 'gear2_6'
			//D1 off, D2 on
			puts("function gear2_6\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_7") == 0)
		{
			//command 'gear2_7'
			//D1 off, D2 on
			puts("function gear2_7\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_8") == 0)
		{
			//command 'gear2_8'		
			//D1 off, D2 on
			puts("function gear2_8\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear2_9") == 0)
		{
			//command 'gear 2_9'
			//D1 off, D2 on
			puts("function gear2_9\n");
			led_control(0, 1);
		}
		else if(strcmp(s, "gear3") == 0)
		{
			//command 'gear3'
			//D1 on, D2 off
			puts("function gear3\n");
			led_control(1, 0);
		}
		else if(strcmp(s, "gear4") == 0)
		{
			//comand 'gear4'
			//D1 on, D2 on
			puts("function gear4\n");
			led_control(1, 1);
		}
		close(client_fd);	
		exit(0);		
          }
	  else
	  {
	  	close(client_fd);
	  }
     }
} 

//PC端 Win Form窗体程序
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace 离子色谱仪
{
    public partial class Form1 : Form
    {
        public static Socket ClientSocket;
        String IP = "192.168.137.243";//友善之臂的IP地址
        string command = "";//即将发送至友善之臂的命令
        public Form1()
        {
            InitializeComponent();
        }
        public void create_command()//生成操作命令
        {
            if (rb_volt.Checked == true)//"电压档"选中
            {
                command = "gear1";
            }
            else if (rb_conductivity.Checked == true)//"电导率档"选中
            {
                if (rb_gear1.Checked == true)
                {
                    command = "gear2_1";
                }
                else if (rb_gear2.Checked == true)
                {
                    command = "gear2_2";
                }
                else if (rb_gear3.Checked == true)
                {
                    command = "gear2_3";
                }
                else if (rb_gear4.Checked == true)
                {
                    command = "gear2_4";
                }
                else if (rb_gear5.Checked == true)
                {
                    command = "gear2_5";
                }
                else if (rb_gear6.Checked == true)
                {
                    command = "gear2_6";
                }
                else if (rb_gear7.Checked == true)
                {
                    command = "gear2_7";
                }
                else if (rb_gear8.Checked == true)
                {
                    command = "gear2_8";
                }
                else if (rb_gear_auto.Checked == true)
                {
                    command = "gear2_9";
                }
            }
            else if (rb_current.Checked == true)//"电流mA挡"选中
            {
                command = "gear3";
            }
            else if (rb_zero.Checked == true)//"调零mV档"选中
            {
                command = "gear4";
            }
        }
        public void send_message()//向友善之臂开发板发送数据
        {
            int port = 3333;

            IPAddress ip = IPAddress.Parse(IP);  //将IP地址字符串转换成IPAddress实例
            ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//使用指定的地址簇协议、套接字类型和通信协议
            IPEndPoint endPoint = new IPEndPoint(ip, port); // 用指定的ip和端口号初始化IPEndPoint实例
            ClientSocket.Connect(endPoint);  //与远程主机建立连接


            //Console.WriteLine("开始发送消息");
            byte[] message = Encoding.ASCII.GetBytes(command);  //通信时实际发送的是字节数组,所以要将发送消息转换字节
            ClientSocket.Send(message);
            //Console.WriteLine("发送消息为:" + Encoding.ASCII.GetString(message));
            byte[] receive = new byte[200];
            int length = ClientSocket.Receive(receive);  // length 接收字节数组长度
            Console.WriteLine("接收消息为:" + Encoding.ASCII.GetString(receive));
            ClientSocket.Close();  //关闭连接
        }
        private void btn_send_Click(object sender, EventArgs e)
        {
            DialogResult dialogResult = MessageBox.Show("确认要发送命令吗?","发送确认",MessageBoxButtons.OKCancel,MessageBoxIcon.Question);
            if (dialogResult == DialogResult.OK)
            {
                create_command();//生成命令
                send_message();//发送命令
            }
            else
            {
                ;//无动作
            }
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {

        }
    }
}

附: 通过Linux虚拟机远程控制ARM开发板的流程: 

1. 找到一台装有图形界面的linux操作系统的ARM开发板.
2. 开启PC机热点.
3. 开机后,按下Ctrl + Alt + T打开终端.
4. 在终端内输入ifconfig以查看ARM开发板的IP地址.
    当前ARM开发板的IP地址为192.168.137.178.
5. 在PC机端(ubuntu虚拟机)的终端内输入ping 192.168.137.178.
    若能ping通,则说明ARM开发板和ubuntu虚拟机已建立连接.
6. 在ARM开发板的终端内输入ssh [email protected](pi为开发板登录用户名).
7. 输入密码pi.
8. 连接已建立.
9. 按下exit退出连接.
 

 

你可能感兴趣的:(FriendlyArm,FriendlyArm,C#,socket通信)