ESP32學(xué)習(xí)筆記(8)——TCP客戶端

一、TCP與UDP優(yōu)缺點

1囱稽、TCP面向連接(如打電話要先撥號建立連接);UDP是無連接的郊尝,即發(fā)送數(shù)據(jù)之前不需要建立連接。

2战惊、TCP提供可靠的服務(wù)流昏。也就是說,通過TCP連接傳送的數(shù)據(jù)吞获,無差錯况凉,不丟失,不重復(fù)各拷,且按序到達;UDP盡最大努力交付刁绒,即不保證可靠交付。
TCP通過校驗和撤逢,重傳控制膛锭,序號標(biāo)識粮坞,滑動窗口蚊荣、確認(rèn)應(yīng)答實現(xiàn)可靠傳輸。如丟包時的重發(fā)控制莫杈,還可以對次序亂掉的分包進行順序控制互例。

3、UDP具有較好的實時性筝闹,工作效率比TCP高媳叨,適用于對高速傳輸和實時性有較高的通信或廣播通信。

4关顷、每一條TCP連接只能是點到點的;UDP支持一對一糊秆,一對多,多對一和多對多的交互通信议双。

5痘番、TCP對系統(tǒng)資源要求較多,UDP對系統(tǒng)資源要求較少。

二汞舱、概述

ESP-IDF使用開源 lwIP輕量級的TCP / IP堆棧伍纫。ESP-IDF版本lwIP(esp-lwip)與上游項目相比有一些修改和補充。

ESP-IDF支持以下功能 lwIP TCP / IP堆棧功能:

BSD套接字API

BSD套接字API是一個通用的跨平臺TCP / IP套接字API莹规,該API起源于UNIX的Berkeley標(biāo)準(zhǔn)發(fā)行版,但現(xiàn)在已在POSIX規(guī)范的一部分中進行了標(biāo)準(zhǔn)化泌神。BSD套接字有時稱為POSIX套接字或Berkeley套接字良漱。

正如ESP-IDF中實施的那樣,lwIP支持BSD套接字API的所有常用用法欢际。

ESP-IDF 編程指南——ESP-NETIF
ESP-IDF 編程指南——lwIP

三债热、API說明

以下 BSD Socket 接口位于 lwip/lwip/src/include/lwip/sockets.h

  • socket()
  • bind()
  • accept()
  • shutdown()
  • getpeername()
  • getsockopt()setsockopt()(請參閱套接字選項
  • close()(通過虛擬文件系統(tǒng)組件
  • read()幼苛,readv()窒篱,write()writev()(經(jīng)由虛擬文件系統(tǒng)部件
  • recv()舶沿,recvmsg()墙杯,recvfrom()
  • send()sendmsg()括荡,sendto()
  • select()(通過虛擬文件系統(tǒng)組件
  • poll()(注意:在ESP-IDF上高镐,poll()是通過內(nèi)部調(diào)用select來實現(xiàn)的,因此畸冲,select()如果有可用的方法選擇嫉髓,建議直接使用。)
  • fcntl()(請參閱fcntl

非標(biāo)準(zhǔn)功能:

  • ioctl()(請參閱ioctls

四邑闲、TCP客戶端

4.1 主要流程


4.1.1 第一步:新建socket

int addr_family = 0;
int ip_protocol = 0;

addr_family = AF_INET;
ip_protocol = IPPROTO_IP;

int sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
if(sock < 0) 
{
    ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
    // 新建失敗后算行,關(guān)閉新建的socket,等待下次新建
    close(sock);
}

4.1.2 第二步:配置將要連接的服務(wù)器信息(端口和IP)

#define TCP_SERVER_ADRESS    "192.168.61.217"    // 要連接TCP服務(wù)器地址
#define TCP_PORT             3333                // 要連接TCP服務(wù)器端口號

struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr(TCP_SERVER_ADRESS);
dest_addr.sin_port = htons(TCP_PORT);

4.1.3 第三步:連接服務(wù)器

int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr);
if(err != 0) 
{
    ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
    // 連接失敗后苫耸,關(guān)閉之前新建的socket州邢,等待下次新建
    close(sock);
}

4.1.4 第四步:接收數(shù)據(jù)

char rx_buffer[128];

while (1) 
{
    ······
    int len = recv(sock, rx_buffer, sizeof(rx_buffer), 0);
    // Error occurred during receiving
    if (len < 0) 
    {
        ESP_LOGE(TAG, "recv failed: errno %d", errno);
        break;
    }
    // Data received
    else 
    {
        memset(rx_buffer, 0, sizeof(rx_buffer));
        ESP_LOGI(TAG, "Received %d bytes from %s:", len, TCP_SERVER_ADRESS);
        ESP_LOGI(TAG, "%s", rx_buffer);
    }
}

4.1.5 第五步:發(fā)送數(shù)據(jù)

static const char *payload = "Message from ESP32 ";

int err = send(sock, payload, strlen(payload), 0);
if (err < 0) 
{
    ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
}

4.2 配置SSID和密碼連接WIFI創(chuàng)建TCP客戶端


使用 esp-idf\examples\protocols\sockets\tcp_client 中的例程

/* BSD Socket API Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"


#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif

#define PORT CONFIG_EXAMPLE_PORT

static const char *TAG = "example";
static const char *payload = "Message from ESP32 ";

static void tcp_client_task(void *pvParameters)
{
    char rx_buffer[128];
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;

    while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
        struct sockaddr_in dest_addr;
        dest_addr.sin_addr.s_addr = inet_addr(host_ip);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(PORT);
        addr_family = AF_INET;
        ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
        struct sockaddr_in6 dest_addr = { 0 };
        inet6_aton(host_ip, &dest_addr.sin6_addr);
        dest_addr.sin6_family = AF_INET6;
        dest_addr.sin6_port = htons(PORT);
        dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
        addr_family = AF_INET6;
        ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
        struct sockaddr_in6 dest_addr = { 0 };
        ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
        int sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
        if (sock < 0) {
            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);

        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
        if (err != 0) {
            ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Successfully connected");

        while (1) {
            int err = send(sock, payload, strlen(payload), 0);
            if (err < 0) {
                ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
                break;
            }

            int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
            // Error occurred during receiving
            if (len < 0) {
                ESP_LOGE(TAG, "recv failed: errno %d", errno);
                break;
            }
            // Data received
            else {
                rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
                ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
                ESP_LOGI(TAG, "%s", rx_buffer);
            }

            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }

        if (sock != -1) {
            ESP_LOGE(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());

    xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}

idf.py menuconfig 配置服務(wù)器IP和端口


配置SSID和密碼



然后 idf.py flash 編譯下載

查看打印:


4.3 使用SmartConfig連接WIFI創(chuàng)建TCP客戶端


根據(jù) esp-idf\examples\protocols\sockets\tcp_client 中的例程修改

/* BSD Socket API Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "esp_smartconfig.h"

#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif

#define PORT CONFIG_EXAMPLE_PORT

static const char *TAG = "example";
static const char *payload = "Message from ESP32 ";

/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;

/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t s_wifi_event_group;

static void smartconfig_example_task(void * parm);
static void tcp_client_task(void *pvParameters);

static void event_handler(void* arg, esp_event_base_t event_base, 
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
        ESP_LOGI(TAG, "Scan done");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
        ESP_LOGI(TAG, "Found channel");
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
        ESP_LOGI(TAG, "Got SSID and password");

        smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
        wifi_config_t wifi_config;
        uint8_t ssid[33] = { 0 };
        uint8_t password[65] = { 0 };

        bzero(&wifi_config, sizeof(wifi_config_t));
        memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
        memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
        wifi_config.sta.bssid_set = evt->bssid_set;
        if (wifi_config.sta.bssid_set == true) {
            memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
        }

        memcpy(ssid, evt->ssid, sizeof(evt->ssid));
        memcpy(password, evt->password, sizeof(evt->password));
        ESP_LOGI(TAG, "SSID:%s", ssid);
        ESP_LOGI(TAG, "PASSWORD:%s", password);

        ESP_ERROR_CHECK( esp_wifi_disconnect() );
        ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
        ESP_ERROR_CHECK( esp_wifi_connect() );
    } else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
        xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
    }
}

static void initialise_wifi(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    s_wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
    assert(sta_netif);

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );

    ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
    ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );

    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}

static void smartconfig_example_task(void * parm)
{
    EventBits_t uxBits;
    ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS) );
    smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
    while (1) {
        uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY); 
        if(uxBits & CONNECTED_BIT) {
            ESP_LOGI(TAG, "WiFi Connected to ap");
        }
        if(uxBits & ESPTOUCH_DONE_BIT) {
            ESP_LOGI(TAG, "smartconfig over");
            xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
            esp_smartconfig_stop();
            vTaskDelete(NULL);
        }
    }
}

static void tcp_client_task(void *pvParameters)
{
    char rx_buffer[128];
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;

    while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
        struct sockaddr_in dest_addr;
        dest_addr.sin_addr.s_addr = inet_addr(host_ip);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(PORT);
        addr_family = AF_INET;
        ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
        struct sockaddr_in6 dest_addr = { 0 };
        inet6_aton(host_ip, &dest_addr.sin6_addr);
        dest_addr.sin6_family = AF_INET6;
        dest_addr.sin6_port = htons(PORT);
        dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
        addr_family = AF_INET6;
        ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
        struct sockaddr_in6 dest_addr = { 0 };
        ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
        int sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
        if (sock < 0) {
            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);

        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
        if (err != 0) {
            ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
            break;
        }
        ESP_LOGI(TAG, "Successfully connected");

        while (1) {
            int err = send(sock, payload, strlen(payload), 0);
            if (err < 0) {
                ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
                break;
            }

            int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
            // Error occurred during receiving
            if (len < 0) {
                ESP_LOGE(TAG, "recv failed: errno %d", errno);
                break;
            }
            // Data received
            else {
                rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
                ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
                ESP_LOGI(TAG, "%s", rx_buffer);
            }

            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }

        if (sock != -1) {
            ESP_LOGE(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    initialise_wifi();
    // ESP_ERROR_CHECK(esp_netif_init());
    // ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    // ESP_ERROR_CHECK(example_connect());

    // xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}

idf.py menuconfig 配置服務(wù)器IP和端口


然后 idf.py flash 編譯下載

查看打油首印:



? 由 Leung 寫于 2021 年 4 月 26 日

? 參考:第十六章 ESP32的TCP連接
    樂鑫Esp32學(xué)習(xí)之旅⑨ esp32上實現(xiàn)本地 TCP 客戶端和服務(wù)端角色量淌,可斷線重連原路返回數(shù)據(jù)
    ESP32 開發(fā)筆記(三)源碼示例 21_WIFI_STA_TCP_Client 在站模式STA下實現(xiàn)TCP客戶端
    ESP32TCP-CLIENT 通信
    ESP32開發(fā)之路(7)---ESP32作為TCP客戶端連接到局域網(wǎng)的PC機

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嫌褪,隨后出現(xiàn)的幾起案子呀枢,更是在濱河造成了極大的恐慌,老刑警劉巖笼痛,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裙秋,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機残吩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門财忽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人泣侮,你說我怎么就攤上這事即彪。” “怎么了活尊?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵隶校,是天一觀的道長。 經(jīng)常有香客問我蛹锰,道長深胳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任铜犬,我火速辦了婚禮舞终,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘癣猾。我一直安慰自己敛劝,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布纷宇。 她就那樣靜靜地躺著夸盟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪像捶。 梳的紋絲不亂的頭發(fā)上上陕,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音拓春,去河邊找鬼释簿。 笑死,一個胖子當(dāng)著我的面吹牛痘儡,可吹牛的內(nèi)容都是我干的辕万。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼沉删,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了醉途?” 一聲冷哼從身側(cè)響起矾瑰,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎隘擎,沒想到半個月后殴穴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年采幌,在試婚紗的時候發(fā)現(xiàn)自己被綠了劲够。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡休傍,死狀恐怖征绎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磨取,我是刑警寧澤人柿,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站忙厌,受9級特大地震影響凫岖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逢净,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一哥放、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爹土,春花似錦婶芭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宰掉,卻和暖如春呵哨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背轨奄。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工孟害, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挪拟。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓挨务,卻偏偏與公主長得像,于是被迫代替她去往敵國和親玉组。 傳聞我的和親對象是個殘疾皇子谎柄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容