Rumah  >  Artikel  >  Tutorial sistem  >  Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

WBOY
WBOYke hadapan
2024-02-05 12:15:27474semak imbas

1 Sesetengah pengawal mikro berprestasi tinggi selalunya mempunyai antara muka Ethernet Port rangkaian dianggap sebagai persisian yang agak kompleks dalam MCU kerana ia melibatkan pengendalian susunan protokol rangkaian. Biasanya, susunan protokol rangkaian akan berjalan dalam sistem pengendalian masa nyata (RTOS), jadi sukar bagi pembangun mikropengawal biasa menggunakan port rangkaian. Di bawah Linux, port rangkaian adalah antara muka yang kerap digunakan, kerana Linux mempunyai susunan protokol komunikasi rangkaian yang matang dan lengkap, dan pemacu asas telah disediakan oleh pengilang, jadi ia agak mudah digunakan. Artikel ini akan meringkaskan secara ringkas penggunaan port rangkaian di bawah Linux, dengan harapan dapat membantu semua orang.

2 Pengenalan Persekitaran

2.1.Perkakasan

1) Papan pembangunan NUC972 yang dibuat oleh pihak ketiga di Internet:

Rakan-rakan yang berminat untuk membeli boleh pergi ke kedai Taobao mereka untuk membeli: Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

https://s.click.taobao.com/X8mza8w

Artikel ini terutamanya berkaitan dengan port rangkaian papan.

2) 1 kabel USB ke RS232, 1 kabel rangkaian, 1 kord kuasa, 1 kabel USB Mikro

2.2.

Perisian

1) Kami terus menggunakan Uboot dan Kernel dari artikel sebelumnya.

2) Kami menggunakan Buildroot untuk menjana semula Rootfs Alamat muat turun NUC972 Buildroot ialah: https://github.com/OpenNuvoton/NUC970_Buildroot Sebab kami menggunakan Buildroot untuk menjana semula Rootfs di sini adalah untuk menggunakan alat Buildroot untuk menambah perkara yang kami. mahu, seperti Fungsi ssh yang kami perlukan dalam artikel ini akan menjadi sangat mudah, dan ia lebih mudah daripada memindahkannya secara manual. Mungkin anda tidak memahaminya Jika anda berminat, anda boleh merujuk kepada tutorial dalam talian untuk pemindahan dropbear secara manual untuk melaksanakan fungsi ssh Dengan membandingkan kedua-dua kaedah, anda akan mempunyai pemahaman yang mendalam.

3) Rantai alat silang arm_linux_4.8.tar.gz masih digunakan dalam artikel sebelum ini, saya rasa rantaian alat ini juga dihasilkan oleh Buildroot.

3Buildroot membuat Rootfs

Langkah terperinci tidak lagi diperkenalkan di sini Anda boleh merujuk kepada artikel yang saya siarkan sebelum "Menggunakan Buildroot untuk Membuat Sistem Fail Root untuk I.MX6".

1) Selepas memuat turun Buildroot rasmi, masukkan direktori yang sepadan dan laksanakan arahan berikut:

buat nuvoton_nuc972_defconfig

buat

Masa kompilasi pertama akan lama sedikit, semua orang mesti bersabar, kerana ia akan memuat turun banyak fail dalam talian.

2) Mengenai isu rantai alat silang, rantai alat Buildroot digunakan Memilih Buildroot ini akan mencipta rantai alat dari awal. Selepas penyusunan selesai, anda dapat melihat bahawa akan ada rantai alat yang baru dibuat dalam direktori output/host/Saya secara peribadi meneka bahawa rantaian alat rasmi berasal dari ini.

3) Dropbear tidak dipilih dalam konfigurasi lalai, anda boleh memilihnya sendiri.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

4) Selepas kompilasi selesai, rootfs yang dihasilkan adalah output/images/rootfs.tar Untuk dapat memprogramkannya ke dalam papan NUC972, ia perlu dinyahmampat dahulu, dan kemudian gunakan mkyaffs2 untuk menjana . fail format img.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi5) Muat turun semula Uboot, Kernel, Rootfs, dsb. ke papan, konfigurasikan dropbear dan port rangkaian, dan kemudian gunakan arahan passwd untuk menetapkan kata laluan untuk pengguna root ia boleh menghalang sesiapa sahaja daripada log masuk secara langsung.

Sambungkan kabel rangkaian ke papan dan komputer, tetapkan IP komputer kepada 192.168.0.50, dan masukkan ifconfig eth0 192.168.0.100 dalam antara muka log masuk port bersiri Untuk memastikan rangkaian tersedia selepas but, tambahkan ayat ini /etc/init.d/ rcS hujung fail. Dengan cara ini, kita tidak perlu menyambungkan port bersiri kemudian. Kita boleh log masuk ke sistem Linux menggunakan port rangkaian sahaja. Pada masa yang sama, kita boleh memindahkan fail ke papan melalui cakera U seperti sebelumnya, dan kecekapan akan bertambah baik.

4 operasi port rangkaian

4.1.Arahan berkaitan

Untuk arahan berkaitan rangkaian, perintah yang biasa digunakan termasuk ifconfig, yang digunakan semasa mengkonfigurasi kad rangkaian sebelum ini, dan ping, yang digunakan untuk menguji sama ada rangkaian itu boleh diakses, yang lain termasuk laluan, ethtool, dsb., yang akan menjadi diperkenalkan kemudian apabila ia benar-benar digunakan.

4.2.CBahasaContoh

Udp dan tcp komunikasi paling biasa digunakan Pengenalan asas kepada mereka tidak akan diperincikan di sini. Di sini kita mengambil UDP sebagai contoh. Mari kita lihat contoh yang sangat klasik.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Fungsi yang akan dilaksanakan ialah:

1) Pelanggan menerima data yang dimasukkan secara manual

2) Pelanggan menghantar data di atas ke Pelayan

3) Pelayan menghantar semula data yang diterima kepada Pelanggan

Pergi terus ke kod:

/***********************************************
 * @{
 * @file  : udp_client.c
 * @brief : 
 * @author: TopSemic
 * @email : topsemic@sina.com
 * @date  : 2019-06-20
***********************************************/

//--------------------------------------------------
// Copyright (c) Topsemic
//--------------------------------------------------
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  

#define SEND_DEST_PORT 8888


int main()
{
  int sockfd;
  int ret;
  struct sockaddr_in addr_sender;
  struct sockaddr_in addr_dest;
  
  int nlen = sizeof(struct sockaddr);
  int recvlen=0;  
    
    // sender address  
    bzero(&addr_sender,sizeof(addr_sender));
    
  // dest address
  bzero(&addr_dest,sizeof(struct sockaddr_in));//每个字节都用0填充
  addr_dest.sin_family=AF_INET;  
    addr_dest.sin_addr.s_addr=inet_addr("127.0.0.1");
     addr_dest.sin_port=htons(SEND_DEST_PORT); 

  sockfd=socket(AF_INET,SOCK_DGRAM,0); //udp 创建套接字
  if(sockfd printf("create socket failure,sockfd:%d\n",sockfd);
    return -1;

  }
  
  //不断获取用户输入并发送给服务器,然后接受服务器数据
  while(1)
  {
    char buff[1024] = {0x00};
    printf("Please Input a string: ");
    fgets(buff,1024,stdin);
    
    sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr*)&addr_dest, sizeof(struct sockaddr_in));
    
    recvlen = recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&addr_sender,(socklen_t *)&nlen);
    
      if(recvlen > 0)
    {
      buff[recvlen] = 0x00;
      printf("Message form server: %s\n", buff);
      printf("sender ip:%s port:%d\n",inet_ntoa(addr_sender.sin_addr),ntohs(addr_sender.sin_port));
    }
    printf("**************************************\n");
  }
  
  close(sockfd);
  return 0;
}

Mula-mula kami menggunakan gcc untuk menyusun dalam Ubuntu Sila ambil perhatian bahawa kami tidak menyusun silang arm-linux-gcc kita mahu.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Anda boleh melalui kod di atas dengan teliti Terdapat beberapa perkara yang memerlukan penjelasan:

1) UDP berbeza daripada TCP kerana tiada sambungan permintaan dan proses penerimaan, jadi dalam praktiknya tidak ada perbezaan yang jelas antara pelayan dan klien Penamaan pelayan dan klien di atas hanyalah untuk kemudahan penerangan bagaimana saya memahaminya: hantar data dahulu ( Pelanggan menerima data selepas meminta data), dan pelayan menerima data dahulu dan kemudian menghantar data.

2) Adakah anda perasan bahawa fungsi bind dipanggil dalam contoh pelayan, tetapi tidak dalam contoh klien Apakah sebabnya? Sebabnya ialah ini, kerana pelayan mesti menerima data terlebih dahulu untuk berfungsi Jika port tidak terikat, tidak ada cara untuk mengetahui di mana untuk menerima data. Sebab mengapa Klien tidak perlu mengikat adalah kerana ia menghantar dahulu, dan boleh menerima data di port penghantaran serta-merta selepas menghantar.

3) Dalam kerja sebenarnya, saya dapati ramai orang termasuk saya sendiri sering keliru dengan port. Untuk meringkaskan di sini, apabila menerima UDP, anda perlu mengikat nombor port (port peranti port ini sendiri) sebelum anda boleh menerima data daripada port ini Selepas menerima data, anda akan mendapat alamat IP pihak lain dan nombor port yang dihantar . Hanya nyatakan IP dan port pihak lain semasa menghantar Port penghantaran mesin ini ditetapkan secara rawak, dan tidak perlu mengikat port.

Untuk mengesahkan bahawa port yang dihantar tanpa mengikat port ditetapkan secara rawak, kami boleh melakukan satu lagi percubaan kecil Kami mematikan Pelanggan dan membukanya semula Kami melihat maklumat port yang dicetak dua kali sebelum dan selepas nombor port adalah berbeza.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

4) Apabila memanggil soket untuk mencipta soket, parameter kedua fungsi diluluskan SOCK_DGRAM, menunjukkan bahawa protokol UDP digunakan. Jika ia TCP, parameternya ialah SOCK_STREAM.

5) Gunakan htonl(INADDR_ANY) untuk mendapatkan alamat IP secara automatik apabila memberikan nilai kepada pembolehubah ahli addr_local.

Kelebihan menggunakan INADDR_ANY ialah apabila perisian berjalan pada hos lain atau alamat IP hos berubah, tidak perlu menukar kod sumber dan menyusun semula, dan tidak perlu memasukkannya secara manual semasa memulakan perisian. Selain itu, jika berbilang alamat IP telah diberikan kepada satu hos, data boleh diterima daripada alamat IP yang berbeza selagi nombor port adalah konsisten.

6) IP yang kami tetapkan semasa menghantar dalam Klien ialah 127.0.0.1, iaitu alamat IP khas Anda boleh menggunakan ifconfig untuk melihatnya di bawah Ubuntu dan pada papan:

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Saya menemui penerangan bahasa Inggeris dari Internet:

127.0.0.1 ialah alamat protokol Internet (IP) gelung balik yang juga dirujuk sebagai "host tempatan". sebagai Mewakili mesin tempatan itu sendiri.

Langkah seterusnya, kami akan menyusun silang kod Pelanggan dan meletakkannya di papan untuk menjalankannya Kami perlu membuat dua perubahan halus:

Addr_dest.sin_addr.s_addr=inet_addr(“127.0.0.1”); ditukar kepada:

addr_dest.sin_addr.s_addr=inet_addr(“192.168.0.50”);

192.168.0.50 ialah alamat IP PC.

Tiga ayat ini dalam kedua manakala(1)

char buff[1024] = {0x00};

printf("Sila Masukkan rentetan: ");

fgets(buff,1024,stdin);

ditukar kepada:

char buff[1024] = “Hello Rakan TopSemic!”;

//printf("Sila Masukkan rentetan: ");

//fgets(buff,1024,stdin);

Tujuannya adalah untuk membolehkan pelanggan menghantar dan menerima data secara automatik tanpa menunggu pengguna memasukkan maklumat.

Di Ubuntu, gunakan arahan scp untuk terus meletakkan fail ke dalam direktori /opt papan

scp udp_client root@192.168.0.100:/opt

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Selain itu, kami log masuk ke sistem Linux terus melalui arahan ssh di bawah Ubuntu

ssh root@192.168.0.100:/opt

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Untuk keluar, hanya masukkan keluar untuk kembali ke tetingkap baris arahan Ubuntu.

Dengan cara ini, proses log masuk ke papan dan memuat naik fail ke papan boleh dikendalikan dengan mudah di Ubuntu Berbanding dengan log masuk port bersiri Windows dan pemindahan fail cakera U, ia adalah lebih mudah.

Saya sangat gembira apabila saya menjalankan udp_server di bawah Ubuntu saya log masuk ke papan dengan ssh di bawah Ubuntu dan menjalankan udp_client saya fikir ia akan berjalan dengan jayanya, tetapi sesuatu yang tidak dijangka berlaku.

Tetapi jelas sekali mesin maya Ubuntu boleh log masuk ke papan dan boleh ping dengan jayanya, dan papan juga boleh ping IP 192.168.0.50, kenapa udp tidak dapat melaluinya? Kemudian, selepas tempoh berfikir, masalah itu diselesaikan. Penyelesaiannya adalah seperti berikut:

Mod tetapan rangkaian lalai mesin maya ialah mod NAT yang ditunjukkan di bawah,

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Kami mengubah suainya kepada mod jambatan seperti yang ditunjukkan di bawah:

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Kemudian cabut kabel rangkaian dan sambungkannya semula, dan ubah suai konfigurasi rangkaian dalam mesin maya Ubuntu

Siri Linux Terbenam Bahagian 8: Port Rangkaian OperasiSiri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Tukar sambungan berwayar mesin maya kepada IP tetap yang dikonfigurasikan secara manual, segmen rangkaian 192.168.0.xx (jangan bercanggah dengan Windows dan IP papan). Anda boleh menggunakan ifconfig untuk mengesahkan sama ada tetapan itu berjaya

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Pada masa ini, log masuk ke papan dan ping 192.168.0.80, dan anda boleh ping dengan jayanya. Sebelum ini, saya ping 192.168.0.50 Itu adalah IP hos Windows Jika ia boleh disambungkan, ia tidak bermakna ia boleh disambungkan ke mesin maya.

Akhir sekali, tukar IP dalam kod di atas,

addr_dest.sin_addr.s_addr=inet_addr(“192.168.0.80”);

Kompil semula, muat turun dan jalankannya sekali, dan ia akan berfungsi seperti biasa.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Titik tambahan: Semasa menyahpepijat papan, saya sering menggunakan pembantu penyahpepijatan rangkaian di bawah Windows Untuk menggunakan alat ini, anda hanya perlu mengkonfigurasi jenis protokol, alamat hos tempatan, port hos tempatan dan hos jauh, dan kemudian hantar. itu, dan anda boleh melihat hasilnya.

Sebagai contoh, kami juga boleh mendayakan pembantu penyahpepijatan rangkaian dalam Windows untuk mensimulasikan komunikasi antara klien dan pelayan mesin maya, seperti berikut:

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

5 Ringkasan kerja amali

Sebutkan kesilapan biasa yang mudah dilakukan dalam kerja sebenar.

Andaikan pemproses anda berkomunikasi dengan peranti luaran melalui port rangkaian, menggunakan kaedah komunikasi UDP Aliran kerja biasa adalah seperti yang ditunjukkan di bawah anda mula-mula menghantar data, dan kemudian peranti luaran bertindak balas kepada anda.

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

Model ini hampir sama dengan model Pelayan dan Pelanggan yang disebutkan di atas Apa yang anda ingin laksanakan ialah Klien. Iaitu, panggil fungsi sendto untuk menghantar dahulu, dan kemudian panggil fungsi recvfrom untuk menerima. Dalam keadaan biasa, tiada masalah untuk menulis program seperti ini, tetapi dalam praktiknya anda perlu mempertimbangkan banyak situasi tidak normal, seperti peranti luaran tiba-tiba dimatikan dan kemudian dihidupkan atau dimulakan semula semasa operasi biasa (tetapi peranti CPU anda tidak berkuasa off). Ini Apakah masalah yang akan timbul? Oleh kerana peranti luaran dimatikan, fungsi recvfrom akan menyekat kerana ia tidak dapat menerima data Walaupun selepas peranti luaran dikuasakan semula dan dimulakan, ia tidak akan memberikan data respons kerana ia belum menerima data, menyebabkan fungsi recvfrom anda menjadi. tersangkut tidak bergerak.

Jika kod sedemikian dikeluarkan ke tapak, ia akan membawa bahaya tersembunyi yang besar, kerana keadaan di atas berlaku di tapak Sebagai contoh, jika peranti CPU anda dihidupkan dahulu dan peranti luaran dihidupkan kemudian. masalah di atas juga akan berlaku. Dalam projek saya sebelum ini, masalah ini menyebabkan pelanggan mengadu tentang masalah produk Pelanggan mendapati bahawa jika komunikasi gagal, masalah itu hanya boleh diselesaikan dengan mematikan peranti semula.

解决上述问题的办法也很简单,可以设置一个超时,使用setsockopt函数,让接收函数在超时时间内没有接收到数据时就返回就行了。返回后再接着重头发送数据即可,框架如下:

/* 设置阻塞超时 */

struct timeval timeout = {3, 0}; // 设置3s超时

if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval))

{

<code style="display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px">printf("time out setting failed ");
</code>

}

.

.

.

/* 数据阻塞接收 */

int receivePacketLen = recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)& addr_sender,&addrLen);

if(receivePacketLen != -1)

{

//接收到数据

}

else if (errno == EAGAIN) //阻塞接收超时

{

<code style="display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px">printf("udp receive timeout! ");

return -1;
</code>

}

为了大家更直观的感受这个问题,我们在上面实验的基础上来模拟这个场景,我们先运行upd_client,后运行udp_server,大家看下现象,结果自然是没有数据输出。

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

道理不难想明白,client程序运行后,先发送了数据,然后就阻塞在读那里不动了。我们把程序简单修改下:

// Max Recv block timeout in second
#define gMaxRecvBlockTimeout 3
…
…
…
// Set recv timeout
   struct timeval timeout = {gMaxRecvBlockTimeout, 0};
   if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(struct timeval)) printf("time out setting failed ");
   }


//不断获取用户输入并发送给服务器,然后接受服务器数据
while(1)
{
char buff[1024] = "Hello TopSemic Friends!";
//printf("Please Input a string: ");
//fgets(buff,1024,stdin);


sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr*)&addr_dest, sizeof(struct sockaddr_in));
recvlen = recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&addr_sender,(socklen_t *)&nlen);
   if(recvlen > 0)
{
buff[recvlen] = 0x00;
printf("Message form server: %s ", buff);
printf("sender ip:%s port:%d ",inet_ntoa(addr_sender.sin_addr),ntohs(addr_sender.sin_port));
}
else if(errno == EAGAIN) // 阻塞接收超时
       {
           printf("udp receive timeout! ");
       }
printf("************************************** ");
}


close(sockfd);
    return 0;

这时我们先运行client,

Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi

打印如上,然后再运行Server,就可以正常工作了,不会再出现上述问题。

Atas ialah kandungan terperinci Siri Linux Terbenam Bahagian 8: Port Rangkaian Operasi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:lxlinux.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam