Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
网络学习营
socket
tcp
【网络编程学习】+ zppsky + 实现一个简单的 TCP 聊天客户端
发布于 2018-08-02 00:42:24 浏览:1641
订阅该版
[tocm] # 实现一个简单的 TCP 聊天客户端 ## 1.开发环境 (1)实验平台:QEMU (2)软件版本:RT-Thread3.1.0 (3)编译工具:env_released_0.7.0 ## 2.作业要求 (1)背景![1.PNG](/uploads/201808/02/001812znzni3bin3bambmi.png) (2)要求![2.PNG](/uploads/201808/02/001812g66u68xzbobfc6q6.png) ## 3.开发过程以及结果 通过网络调试助手作为客户端发送各个命令,查看服务器应答客户端命令的特点。客户端与服务器建立连接成功后,服务器会下发一条信息“Welcometo TestChat”,因此,在建立连接成功后,需要接收一次服务器信息。 “look”和“who”命令的应答分两次发送给客户端,首先发送提示信息,然后再发具体的信息(登录聊天室的所有用户ID)。故对于客户端发送完这两条命令后,需要接收两次服务器的应答信息。 “login”和“logout”命令没有返回信息,因此,发送这两条信息后,不需要去接收应答信息。整体是通过一个函数实现了所有功能,然后通过MSH_CMD_EXPORT()函数导出命令,使得客户端可以在msh中通过命令启动运行。 (1)基于命令行的客户端 对于基于命令行的客户端,每发送一次命令后,则接收并显示服务应答信息。实现的聊天客户端运行结果如下图。(缺点是,如果有其他用户与服务器进行通信,则会出现紊乱)。 ![3.PNG](/uploads/201808/02/001812b7nlt6iebnhbenu7.png) (2)所有命令统一执行 由于题目说明是通过代码实现所有步骤,因此将各个命令在代码中写好,运行客户端后,依次实现与服务器通信的过程。创建命令组如下图所示。每次发送命令时,依次从这个命令组中取。 ![4.PNG](/uploads/201808/02/001812zviabmpbwybm6syw.png) 发送“look”命令查看聊天室的用户,得到所有用户ID需要暂时存起来,用于告诉服务器客户端查看到所有用户的命令中。在构建告诉服务器查看到的所有用户ID的命令时,需要将命令组中的相应命令与得到的用户命令进行拼接,然后发送给服务器。命令拼接处理如下所示。首先查看命令首字符判断此条命令是否是通知服务查看到所有用户的命令(字符为“#”),如果是,则进行拼接处理。在命令中出现“$”字符处加入查看到的所有用户ID。具体可查看代码。 ![5.PNG](/uploads/201808/02/001813eiwksjzdiffd5oom.png) 实现的聊天客户端运行结果如下图 ![6.PNG](/uploads/201808/02/001813ki3c4cow4iwcioog.png) ## 4.总结 通过此次学习和做任务,学习了网络通信方面的知识,并编程实现了一个能够与服务器简单通信的客户端程序,将理论用于实践,对网络编程有更进一步的理解。 在学习过程中遇到一些问题问题与解决方法进行总结。 (1)找不到功能菜单在Evn环境下,输入menuconfig命令,按照菜单逐步去开启`“[network]tcp client”`,结果找不到相应的菜单 ![7.PNG](/uploads/201808/02/001813m0lhfbq6mn00z4qj.png) ![8.PNG](/uploads/201808/02/001813p2p3c5y5ilailu12.png) ### 问题解决 退出menuconfig界面,然后输入**“pkgs--upgrade”,**更新本地软件包,完成后,再进入menuconfig界面按照步骤来,即然后可以找到相应的菜单 (2)安装好wireshark后不显示网卡系统信息 Windows10 64位操作系统 Wireshark版本:Version 2.6.2 (v2.6.2-0-g1b3cedbc) ![9.PNG](/uploads/201808/02/001813lbr0jwtvb5kkw0s9.png) ### 解决方法 第一步 1、打开windows设备管理器。 2、查看-显示隐藏的设备 3、非即插即用驱动程序 4、`NetGroup Packet Filter Driver` 右键属性---驱动程序---启动类型,修改类型为“系统” 第二步 在cmd下输入`net start npf`,打开网络抓包服务 (执行时如果遇到权限问题,可在`C:\Windows\System32`目录下右键`–>`以管理员权限执行`cmd.ext`,让后在cmd里执行上述命令即可。) 第三步 运行`wireshark`,此时网卡已经可以正常检测到了 命令行客户端源码: 附件 - [testchat_tcpclient_init.c](/uploads/201808/02/004148o7yco6mw7uy4t6ox.attach) 所有命令统一执行客户端: 附件 - [testchat_tcpclient_x2.c](/uploads/201808/02/004148ejwsfr4flxkjjprp.attach) **命令统一执行源代码(任务要求)** 显示在页面便于查看 ```c #include
#include
#include
#include
#include
#include "netdb.h" /* define buffer size */ #define BUFSIZE 512 void chat_client(void) { struct sockaddr_in server_addr; const char *url; int port; int ret; char *recv_data = RT_NULL; char *send_data = RT_NULL; struct hostent *host; int sock, bytes_received; char login_flag = 0; int cmd_len = 0; char *cmd_p; char cmd_print[128]; char cmd_temp[128]; char name_recv[128]; int recv_cnt = 0; int send_cnt = 0; int recv_tmp; /* commmand group */ char *send_cmd_group[] = { "Hello,world
", "login zppsky
", "say My name is zppsky, I'm doing this job at 20180801
", "look
", "who
", "#say I can see $ in the room
", "say I am quiting
", "logout
", NULL }; /* the ip of server */ url = "183.193.243.90"; /* port */ port = 11222; /* get host information */ host = gethostbyname(url); /* malloc buffer for receivded data*/ recv_data = rt_malloc(BUFSIZE); if(recv_data == RT_NULL) { rt_kprintf("No memory
"); return; } rt_memset(recv_data, '\0', BUFSIZE); /* create a socket */ if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { rt_kprintf("Socket error
"); rt_free(recv_data); return; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr = *((struct in_addr *)host->h_addr); rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); /* Connect to server */ if(connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) { /* if connect failed */ rt_kprintf("Connect fail!
"); closesocket(sock); rt_free(recv_data); return; } rt_kprintf("Connet to server successfully
"); /* Receive the message from server */ bytes_received = recv(sock, recv_data, BUFSIZE - 1, 0); if(bytes_received < 0) { /* receive falied */ closesocket(sock); rt_kprintf("
received error, close the socket.
"); rt_free(recv_data); return; } else if(bytes_received == 0) { /* receive falied */ closesocket(sock); rt_kprintf("
received error(zero), close the socket.
"); rt_free(recv_data); return; } rt_kprintf("(Message from server): %s
", recv_data); /* get the first command */ send_cnt = 0; send_data = send_cmd_group[send_cnt]; /* Loop for chat */ while(send_data) { if(*send_data == '#') { /* skip the first '#' */ cmd_p = ++send_data; cmd_len = 0;/* reset the length of cmd */ while(*cmd_p != ' ) { cmd_temp[cmd_len++] = *cmd_p++; } /* skip the ' */ cmd_p++; /* get the names in the room */ strncpy(&(cmd_temp[cmd_len]), name_recv, strlen(name_recv)); cmd_len += strlen(name_recv); strncpy(&(cmd_temp[cmd_len]), cmd_p, strlen(cmd_p)); cmd_len += strlen(cmd_p); cmd_temp[cmd_len] = '\0'; send_data = cmd_temp; } /* Send message to server */ ret = send(sock, send_data, strlen(send_data), 0); if(ret < 0) { /* Send failed */ closesocket(sock); rt_kprintf("
Send error, close the socket
"); rt_free(recv_data); break; } else if(ret == 0) { rt_kprintf("
Send warning, send function return 0.
"); } /* just for print */ send_data[strlen(send_data) - 2] = '\0'; /* print command message */ rt_kprintf("
", send_data); /* Login successfully */ if((strstr(send_data, "login") != NULL) && (login_flag == 0)) { /* Already login and continue to send next command */ login_flag = 1; /* get the next command */ send_cnt++; send_data = send_cmd_group[send_cnt]; continue; } else if(strstr(send_data, "logout") != NULL) { /* receive falied */ closesocket(sock); rt_kprintf("Logout the chat, close the socket.
"); rt_free(recv_data); break; } recv_cnt = 2; while(recv_cnt--) { /* Receive the message from server */ bytes_received = recv(sock, recv_data, BUFSIZE - 1, 0); if(bytes_received < 0) { /* receive falied */ closesocket(sock); rt_kprintf("
Received error, close the socket.
"); rt_free(recv_data); return; } else if(bytes_received == 0) { /* receive falied */ closesocket(sock); rt_kprintf("
Received error(zero), close the socket.
"); rt_free(recv_data); return; } /* store the names */ if((strstr(send_data, "look") != NULL) && (recv_cnt == 0)) { recv_tmp = 0; while(recv_data[recv_tmp] != '\0') { if((recv_data[recv_tmp] == ' ') || (recv_data[recv_tmp] == '
')) { recv_data[recv_tmp] = ' '; } /* store the names */ name_recv[recv_tmp] = recv_data[recv_tmp]; recv_tmp++; } name_recv[recv_tmp] = '\0'; rt_kprintf("%s
", recv_data); break; } else if((strstr(send_data, "who") != NULL) && (recv_cnt == 0)) { recv_tmp = 0; while(recv_data[recv_tmp] != '\0') { if((recv_data[recv_tmp] == ' ') || (recv_data[recv_tmp] == '
')) { recv_data[recv_tmp] = ' '; } recv_tmp++; } rt_kprintf("%s
", recv_data); break; } /* print the message */ rt_kprintf("(Message from server): %s", recv_data); if((strstr(send_data, "look") != NULL) || (strstr(send_data, "who") != NULL)) { rt_memset(recv_data, 0, BUFSIZE); continue; } else { rt_memset(recv_data, 0, BUFSIZE); break; } } /* get the next command */ send_cnt++; send_data = send_cmd_group[send_cnt]; } } MSH_CMD_EXPORT(chat_client, a tcp client for chat); ```
查看更多
0
个回答
默认排序
按发布时间排序
暂无答案,快来添加答案吧
撰写答案
登录
注册新账号
关注者
0
被浏览
1.6k
关于作者
zppsky16
公众号【一起学嵌入式】,RTOS、Linux、C/C++
提问
9
回答
5
被采纳
0
关注TA
发私信
相关问题
1
【LWIP学习营】第一关开发环境搭建
2
LWIP学习营第一周入门移植问题汇总贴
3
【LWIP学习营】f407+lan8720A小结
4
【LwIP学习营】【第一周】仅零散记录,无主题
5
【LWIP学习营】正点原子探索者F407+LAN8720第一周小结
6
【LwIP学习营】【第一周】网络通信基础及实现TCP 聊天客户端
7
【LwIP学习营】【第一周】LWIP移植
8
【LwIP学习营】【第一周】LWIP移植
9
【LwIP学习营】【第一周】开发板适配
10
【LwIP学习营】【第一周】环境搭建和配置验证
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
a1012112796
13
个答案
1
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部