嵌入式学习-网络-Day02
1.优化代码:
网络问题:
2.1虚拟机网络修复
2.2 网络调试
ping
netstat
3.UDP编程
3.1通信流程
3.2函数接口
1.优化代码:
1.端口和ip地址通过命令行传参到代码中。
2.设置客户端退出,服务器结束循环接收。
通过recv返回值为0判断客户端是否退出
3.设置来电显示功能,获取到请求链接服务器的客户端的ip和端口。
4.设置服务器端自动获取自己的ip地址。
INADDR_ANY "0.0.0.0"
5.实现循环服务器,服务器不退出,当链接服务器的客户端退出,服务器等到下一个客户端链接。
6.去掉fgets获取的多余的'\n'.
if(buf[strlen(buf)-1] == '\n')//去掉fgets获取的'\n'
buf[strlen(buf)-1] ='\0';
server.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define N 128
int main(int argc, char const *argv[])
{
if (argc != 2)
{
printf("please input %s port\n", argv[0]);
return -1;
}
// 1.创建套接字 协议族 类型 协议
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err:");
return -1;
}
// 2.填充结构体(ipv4)
struct sockaddr_in saddr, caddr;
saddr.sin_family = AF_INET; // 协议族ipv4
saddr.sin_port = htons(atoi(argv[1])); // 端口号(网络字节序)
// saddr.sin_addr.s_addr = inet_addr(argv[1]); // ip地址(网络字节序)
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
socklen_t len = sizeof(caddr);
// 3.绑定
int ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0)
{
perror("bind err:");
return -1;
}
// 4.监听
if (listen(sockfd, 5) < 0)
{
perror("listen err");
return -1;
}
while (1)
{
// 5.等待连接
// int acceptfd = accept(sockfd, NULL, NULL);
int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (acceptfd < 0)
{
perror("accpet err:");
return -1;
}
printf("acceptfd = %d\n", acceptfd);
printf("client ip :%s,port:%d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
while (1)
{
// 6.接收
char buf[N] = {};
ret = recv(acceptfd, buf, N, 0);
if (ret == -1)
{
perror("recv err:");
return -1;
}
else if (ret == 0)
{
printf("client exit\n");
break;
}
printf("recv:%s\n", buf);
}
// 7.关闭
close(acceptfd);
}
close(sockfd);
return 0;
}
client.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 128
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("please input %s ip port\n", argv[0]);
return -1;
}
// 1.创建套接字 协议族 类型 协议
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err:");
return -1;
}
// 2.填充结构体(ipv4)
struct sockaddr_in addr;
addr.sin_family = AF_INET; // 协议族ipv4
addr.sin_port = htons(atoi(argv[2])); // 端口号(网络字节序)
addr.sin_addr.s_addr = inet_addr(argv[1]); // ip地址(网络字节序)
//3.连接
if(connect(sockfd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
{
perror("connect err");
return -1;
}
//4.发送
char buf[N]={};
while(1)
{
fgets(buf,sizeof(buf),stdin);
if(buf[strlen(buf)-1] == '\n')
buf[strlen(buf)-1] = '\0';
if(!strncmp(buf,"quit",4))
break;
send(sockfd,buf,N,0);
printf("send ok\n");
}
//5.关闭
close(sockfd);
return 0;
}
网络问题:
2.1虚拟机网络修复
虚拟机网络修复
2.2 网络调试
ping
作为平时网络连通检测使用最多的命令,它的作用主要为:
● 用来检测网络的连通情况;
● 根据域名得到服务器IP;
● 根据ping返回的TTL值来判断数据包经过路由器数量。
字节:数据包大小,也就是字节。
时间:响应时间,这个时间越小,说明你连接这个地址速度越快。
TTL:Time To Live,从源到目的,每经过一个路由器,TTL减1,当TTL=0,包丢掉。
netstat
netstat是控制台命令,是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。Netstat用于显示与IP、TCP、UDP相关的统计数据,一般用于检验本机各端口的网络连接情况。
作用:测试网络状态
netstat -a //查看所有网络连接状态
netstat -at //查看tcp所有网络状态
netstat -au //查看udp所有网络状态
3.UDP编程
3.1通信流程
udp流程:(类似发短信)
server:
创建数据报套接字(socket, (, SOCK_DGRAM,)) ------》有手机
填充结构体(struct ) ---》有号码
绑定 (bind) ---》插卡
接收/发送消息(recvfrom) ----》收、发短信
关闭套接字(close) ---》结束
client:
创建数据报套接字(socket, (, SOCK_DGRAM,)) ------》有手机
填充结构体(struct ) ---》有号码
发送信息(sendto) --->发短信
关闭套接字(close) ---》发送结束
3.2函数接口
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
功能:接收数据
参数:
sockfd:套接字描述符
buf:接收缓存区的首地址
len:接收缓存区的大小
flags:0
src_addr:发送端的网络信息结构体的指针
addrlen:发送端的网络信息结构体的大小的指针
返回值:
成功接收的字节个数
失败:-1
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能:发送数据
参数:
sockfd:套接字描述符
buf:发送缓存区的首地址
len:发送缓存区的大小
flags:0
src_addr:接收端的网络信息结构体的指针
addrlen:接收端的网络信息结构体的大小
返回值:
成功发送的字节个数
失败:-1
代码:
server.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define N 128
int main(int argc, char const *argv[])
{
//1.创建数据报套接字
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{
perror("sock err:");
return -1;
}
//2.填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t len = sizeof(saddr);
//3.绑定
if(bind(sockfd,(struct sockaddr *)&saddr,len) < 0)
{
perror("bind err");
return -1;
}
//4.接收
char buf[N]={};
recvfrom(sockfd,buf,N,0,NULL,NULL);
printf("buf:%s\n",buf);
//5.关闭
close(sockfd);
return 0;
}
client.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define N 128
int main(int argc, char const *argv[])
{
//1.创建数据报套接字
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{
perror("sock err:");
return -1;
}
//2.填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t len = sizeof(saddr);
//3.发送
char buf[N]="hello!";
sendto(sockfd,buf,N,0,(struct sockaddr *)&saddr,len);
printf("send ok\n");
//4.关闭
close(sockfd);
return 0;
}
练习:实现如客户端发送"hello"给服务器端,服务器接着给客户端回,"recv:hello!!!!!"。
server.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 128
int main(int argc, char const *argv[])
{
//1.创建数据报套接字
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd < 0)
{
perror("sock err:");
return -1;
}
//2.填充结构体
struct sockaddr_in saddr,caddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t len = sizeof(saddr);
//3.绑定
if(bind(sockfd,(struct sockaddr *)&saddr,len) < 0)
{
perror("bind err");
return -1;
}
//4.接收
char buf[N]={};
recvfrom(sockfd,buf,N,0,(struct sockaddr *)&caddr,&len);
printf("client ip:%s,port:%d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
printf("buf:%s\n",buf);
strcpy(buf,"hello!!!");
sendto(sockfd,buf,N,0,(struct sockaddr *)&caddr,len);
printf("send ok\n");
//5.关闭
close(sockfd);
return 0;
}
client.c
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 128
int main(int argc, char const *argv[])
{
// 1.创建数据报套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
{
perror("sock err:");
return -1;
}
// 2.填充结构体
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t len = sizeof(saddr);
// 3.发送
// char buf[N]="hello!";
char buf[N] = "";
fgets(buf, N, stdin);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
sendto(sockfd, buf, N, 0, (struct sockaddr *)&saddr, len);
memset(buf, 0, sizeof(buf));
recvfrom(sockfd, buf, N, 0, NULL, NULL);
printf("recvfrom server:%s\n", buf);
printf("send ok\n");
// 4.关闭
close(sockfd);
return 0;
}