在之前几篇中,都是关于系统编程的笔记整理,今天开始整理网络编程部分
IP地址
IP地址是IP协议中用来表示网络中的不同主机的地址;
IP协议有两个版本,PIv4和IPv6,这里默认用是是IPv4
一台主机可能有多个IP地址(与网卡数量或者虚拟网卡数量有关)
通常用点分十进制的字符串表示
端口号
IP地址+端口号能够标识网络中的唯一一台主机的某一个进程
端口号是一个2个字节16位的整数
一个进程可以绑定多个端口号,一个端口号只能被一个进程绑定
初始TCP、UDP协议
网络字节序
机器有大端小端之分,低地址存放数据低字节位小端序列
那么网络中为了统一字节序列,规定网络字节序为大端序列
发送主机是发送数据按照从低地址到高地址的顺序
接收主机也是按照内存中从低地址到高地址的顺序保存的
那么为了能够保证收发数据的准确性,需要调用以下函数来进行网络字节序和主机字节序之间的转换。
#include
uint32_t htonl(uint32_t hostlong); //主机字节序转向网络字节序
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);//网络字节序转向主机字节序
uint16_t ntohs(uint16_t netshort);
h代表主机,n代表网络,l表示32位长整形,s表示16位短整型
并且即使本台机器是大端,也要调用这些函数进行转换,只不过这些函数不做转换而已,也是为了保证代码的可移植性,在不同的机器上面也能正常运行
用到的socket接口
////创建socket文件描述符(客户端+服务器端,TCP/UDP)
//int socket(int domain,int type,int protocol);
////绑定端口号(服务器 TCP/UDP)
//int bind(int socket,const struct sockaddr *address,socklen_t address_len);
//接收对端的数据(服务器+客户端,UDP)
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
//向对端发送数据(服务器+客户端,UDP)
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
#include
#include
#include
#include
#include
#include
//****************UDP*************************
//****************服务器**********************
创建socket文件描述符(客户端+服务器端,TCP/UDP)
//int socket(int domain,int type,int protocol);
绑定端口号(服务器 TCP/UDP)
//int bind(int socket,const struct sockaddr *address,socklen_t address_len);
//接收对端的数据(服务器+客户端,UDP)
//ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
//向对端发送数据(服务器+客户端,UDP)
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
//0,绑定端口号
//1,接收客户端的请求(request)
//2,经过计算处理,做出响应
// 因为此处是echo_server 回显服务,所以省去计算处理,只做以下几步处理
// a)接收到请求后,将其保存下来
// b)显示到标准输出
//3,将响应发送给客户端
// ./service [IP] [Port]
// 要绑定的IP地址和端口号
int main(int argc ,char * argv[])
{
//判断命令行参数是否正确
if(argc!=3)
{
printf("Usage:./service [IP] [Port]\n");
return 0;
}
//****************创建socket套接字*********************************
int fd=socket(AF_INET,SOCK_DGRAM,0);
if(fd<0)
{
perror("socket");
exit(1);
}
//***************将所要绑定的IP地址和Port信息放到sockaddr_in结构体中
sockaddr_in addr;
addr.sin_family=AF_INET;//指定为IPv4协议
//用到了inet_addr()函数,实现两个功能
//1.将字符串格式的点分十进制的IP地址转换为数字
//2.并且该函数会将主机字节序转换为网络字节序
addr.sin_addr.s_addr=inet_addr(argv[1]);
//要将端口号转换为数字,并且要进行网络字节序的转换
addr.sin_port=htons(atoi(argv[2]));
socklen_t sock_len=sizeof(addr);
//***************服务器绑定端口号*************************************
if((bind(fd,(sockaddr *)&addr,sock_len))<0)
{
perror("bind");
exit(2);
}
printf("bind success\n");
//**************服务器进行事件循环************************************
char buf[1024]={0};
sockaddr_in client;
socklen_t client_len=sizeof(client);
while(1)
{
//1.接收来自客户端的请求
ssize_t read_size=recvfrom(fd,buf,sizeof(buf)-1,0,(sockaddr *)&client,&client_len); //这里的client_len既是输入型参数又是输出型参数
if(read_size<0)
{
//读取错误
printf("读取失败\n");
continue;
}
if(read_size==0)
{
//读到文件结束,表示当前客户端已经关闭socket
printf("read done\n");
return 0;
}
else
{
buf[read_size]='\0';
//2.将收到的内容显示到标准输出
printf("client: %s:%d say %s",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
fflush(stdout);
//3.收到的内容发回给客户端
sendto(fd,buf,read_size,0,(sockaddr *)&client,client_len);
}
}
close(fd);
}
#include
#include
#include
#include
#include
#include
//***************************客户端***************************
//***************************UDP*****************************
//向服务器发送请求
// 发送内容从标准输入读取
//接收服务器的响应
// 将接收的响应显示到标准输出上
// ./client IP Port
// 向哪个服务器发送请求
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
int main(int argc,char * argv[])
{
if(argc!=3)
{
printf("Usage [IP] [Port]\n");
exit(1);
}
//创建socket
int fd=socket(AF_INET,SOCK_DGRAM,0);
if(fd<0)
{
perror("socket");
}
//将要发送给哪个服务器的信息赋值sockaddr_in
sockaddr_in service;
service.sin_family=AF_INET;
service.sin_addr.s_addr=inet_addr(argv[1]);
//将端口号转换位网络字节序
service.sin_port=htons(atoi(argv[2]));
socklen_t service_len=sizeof(service);
//从标准输入读取信息
char buf[1024]={0};
//**************接收服务器的响应************************
while(1)
{
ssize_t read_size=read(0,buf,sizeof(buf)-1);
if(read_size<0)
{
perror("read");
return 1;
}
if(read_size==0)
{
//读取到文件结束
printf("done\n");
}
buf[read_size]='\0';
//***************将读取的内容发送给服务器****************
int send_ret=sendto(fd,buf,read_size,0,(sockaddr *)&service, service_len);
if(send_ret<0)
{
perror("send");
return 1;
}
char service_buf[1024]={0};
read_size=recvfrom(fd,service_buf,sizeof(service_buf)-1,0,NULL,NULL);
if(read_size<0)
{
perror("recvfrom");
return 1;
}
if(read_size==0)
{
printf("read done\n");
}
else
{
buf[read_size]='\0';
printf("service response :%s",service_buf);
fflush(stdout);
}
}
close(fd);
}
完。