فهرست مطالب
در این قسمت با استفاده رابط کاربری Raw کتابخانه LWIP نحوه نوشتن برنامه سوکت بیان شده است. رابط کاربری Raw مبتی بر توابع Callback است. بطوری که کاربر توابع متناظر با هر رویداد نظیر دریافت فریم یا رخداد خطا را مشخص میکند و هسته LWIP هنگامیکه هر یک از رخدادهای موردنظر روی دهد تابع مشخص شده فراخوانی میشود.
در جدول 1 توابعی که رابط کاربری Raw برای کار با سوکت TCPدر اختیار برنامه نویس قرار داده است نشان داده شده است.
در جدول 2 توابع کار با سوکت UDP با رابط کاربری Raw نشان داده شده است.
مثال اول: سوکت TCP Server
در این بخش با استفاده از رابط کاربری Raw برنامه یک TCP Server توسعه داده شده است. در این مثال یک Server به پورت 7 گوش میدهد و پس از ایجاد لینک، دادهای که از Client دریافت کرده است را بررسی میکند. در صورتی که رشته “A” را دریافت کند یک LED را روشن و اگر “B” دریافت کند LED را خاموش میکند و همینطور داده دریافتی را مجددا به Client ارسال میکند.
لازم به ذکر است که چگونگی تنظیم کتابخانه LWIP و پورت Ethernet در قسمتهای قبل بیان شده است. لذا از تکرار آن در بخش خودداری شده و فقط مفاهیم مرتبط با برنامهنویسی سوکت بیان شده است.
در این مثال IP بصورت Static تنظیم شده است.
تابع main برنامه بصورت زیر است:
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Configure the GPIO PG6 as output */
MX_GPIO_Init();
/* Configure the ETH port and LwIP library */
MX_LWIP_Init();
/* initialize TCP Echo Server */
tcp_echoserver_init();
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
در تابع tcp_echoserver_init ابتدا یک سوکت TCP تعریف شده است. سپس به پورت هفت Bind شده است و در نهایت با تابع فراخوانی تابع tcp_listen به حالت کاری Listen میرود و هنگامیکه از هر Client یک درخواست دریافت کرد تابع Callback متناظر با Accept (در اینجا tcp_echoserver_accept) را فراخوانی میکند. کد تابع tcp_echoserver_init بصورت زیر تعریف شده است.
void tcp_echoserver_init(void)
{
/* create new tcp pcb */
tcp_echoserver_pcb = tcp_new();
if (tcp_echoserver_pcb != NULL)
{
err_t err;
/* bind echo_pcb to port 7 (ECHO protocol) */
err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
if (err == ERR_OK)
{
/* start tcp listening for echo_pcb */
tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
/* initialize LwIP tcp_accept callback function */
tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
}
else
{
/* deallocate the pcb */
memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb);
}
}
}
نتیجه برنامه TCP Server Socket
در شکل 6 چگونگی نتیجه این مثال نشان داده شده است. در اینجا از نرم افزار Hercules SETUP utility برای تست استفاده شده است. برای تست برنامه ابتدا IP میکروکنترلر که در قسمت Module IP وارد کرده و سپس بر روی دکمه Connect کلیک کنید. لازم به ذکر است که حتما IP کارت شبکه کامپیوتر را بصورتی که در بخش قبل بیان شد، تنظیم شود.
مثال دوم: سوکت UDP Server
در مثال قبل نحوه راهاندازی TCP Server بیان شد. در این مثال نحوه انجام همان کار با استفاده از UDP Server شرح داده شده است.
تابع main این برنامه بصورت زیر است:
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Configure the GPIO PG6 as output */
MX_GPIO_Init();
/* Configure the ETH port and LwIP library */
MX_LWIP_Init();
/* initialize UDP Echo Server */
udp_echoserver_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
MX_LWIP_Process();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
در این مثال تابع udp_echoserver_init بصورت زیر تعریف شده است. در این یک سوکت UDP تعریف شده و سپس سوکت را به پورت هفت Bind شده است. udp_recv تابع Call-back دریافت را مشخص میکند. هنگامیکه فریم UDP دریافت شود هسته LwIP تابع udp_echoserver_receive_callback را فراخوانی میکند.
void udp_echoserver_init(void)
{
struct udp_pcb *upcb;
err_t err;
/* Create a new UDP control block */
upcb = udp_new();
if (upcb)
{
/* Bind the upcb to the UDP_PORT port */
/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
err = udp_bind(upcb, IP_ADDR_ANY, UDP_SERVER_PORT);
if(err == ERR_OK)
{
/* Set a receive callback for the upcb */
udp_recv(upcb, udp_echoserver_receive_callback, NULL);
}
else
{
udp_remove(upcb);
}
}
}
تابع udp_echoserver_receive_callback نیز بصورت زیر تعریف شده است.
void udp_echoserver_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
{
struct pbuf *p_tx;
/* allocate pbuf from RAM*/
p_tx = pbuf_alloc(PBUF_TRANSPORT,p->len, PBUF_RAM);
if(p_tx != NULL)
{
pbuf_take(p_tx, (char*)p->payload, p->len);
/* Connect to the remote client */
udp_connect(upcb, addr, UDP_CLIENT_PORT);
if (*(uint8_t*)(p_tx->payload) == 'A')
{
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET);
}
else if (*(uint8_t*)(p_tx->payload) == 'B')
{
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET);
}
/* Tell the client that we have accepted it */
udp_send(upcb, p_tx);
/* free the UDP connection, so we can accept new clients */
udp_disconnect(upcb);
/* Free the p_tx buffer */
pbuf_free(p_tx);
/* Free the p buffer */
pbuf_free(p);
}
}
خروجی برنامه UDP Server Socket
- در شکل 7 خروجی این مثال نشان داده شده است. همانطور که ملاحظه میکنید میکروکنترلر داده دریافتی را ارسال نموده است:
مشاهده فریم ها با استفاده از نرم افزار Wireshark
Wireshark بهترین نرمافزار آنالیز پروتکلهای شبکه است که با استفاده از آن میتوان کلیه فریمهای ورودی و خروجی را مشاهده و آنالیز کرد. در اینجا با استفاده از این نرمافزار فریمهای ارسالی و دریافتی مشاهده شده است. در شکل 8 فریمهایی که بین کامپیوتر و میکروکنترلر جابجا شدهاند نشان داده شده است.
main koosh ? 😐
سلام با تشکر از آموزش خوبتون لطفأ اگه امکان داره تابع tcp_echoserver_accept را هم قرار دهید با تشکر
خدانگهدار