Linux网络编程(一)

一、linux socket 基础

任务:

  1. 客户端发送小写字母,服务器返回大写字母。
  2. 客户端发送正确的运算(1 + 3),服务器返回结果
  3. 客户端发送一个数字数组,服务器返回其中最大和最小的值
网络基础

ip地址: 在网络环境中唯一标识一台主机(NAT等除外)

端口号:计算上每个占用一个端口,网络通讯时候,要选择通讯程序的端口号。

socket:在编程程序时候用到,为udp和tcp的上层接口。socket在linux中为一种文件类型(伪文件)。有两个缓冲区,一个读数据,一个写数据,为全双工工作模式。如图:
在这里插入图片描述
注意事项:

  1. socket一定是成对出现的
  2. socket一顶要绑定ip 和端口
  3. 一个文件描述符指向两个缓冲区(一个读缓冲,一个写缓冲)
tcp/ip传输

tcp/ip的传输为大端传输,但是不用的主机大小端不同。在编写网络程序过程中,需要网络字节序和主机字节序的转换

其实函数有:

//该类函数的头文件
#include <arpa/inet.h>

// 主机数转换成无符号长整型的网络字节顺序
uint32_t htonl(uint32_t hostlong);

//是将整型变量从主机字节顺序转变成网络字节顺序
uint16_t htons(uint16_t hostshort);

// 是将一个无符号长整形数从网络字节顺序转换为主机字节顺序,
// ntohl()返回一个以主机字节顺序表达的数。
uint32_t ntohl(uint32_t netlong);

//作用是将一个16位数由网络字节顺序转换为主机字节顺序。
uint16_t ntohs(uint16_t netshort);

注意事项:

  1. 大端:地址值-高位 (高地址-地位)
  2. 小段:低-低 高-高

例:
在这里插入图片描述
大小端的转换的函数:

#include <arpa/inet.h>
//将“点分十进制”转换为“网络直接序”
int inet_pton(int af, const char *src, void *dst);
//将“网络字节序”转换为“点分十进制”
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

在网络编程中,用sockaddr结构体来保存协议和ip。后面演变为sockaddr_in,只是在原基础上添加了一些东西。

struct sockaddr {
//保存使用的协议,一般是AF_xxx格式
	sa_family_t sa_family; 		/* address family, AF_xxx */
//保存目标地址ip地址
	char sa_data[14];			/* 14 bytes of protocol address */
};

struct sockaddr_in {
	__kernel_sa_family_t sin_family; 			/* Address family */  	地址结构类型
	__be16 sin_port;					 		/* Port number */		端口号
	struct in_addr sin_addr;					/* Internet address */	IP地址
	...
}

/***struct sockaddr_in中的struct in_addr结构体***/
struct in_addr {						/* Internet address. */
	__be32 s_addr;
};

客户端需要给服务端发送数据,同时也有接受数据的需求。对于服务端,亦然。对着数据接受和发送,有相应的函数:

/***************数据的接受************/
ssize_t read(int fd,    void *buf, size_t count);
sszie_t recv(int sockfd,void *buf, size_t len, int flags);
/************************************/

/***************数据的发送************/
ssize_t write(int fd,    const void *buf, size_t count);
ssize_t send(int sockfd, const void *buf, size_t len, flags)
/************************************/

注:

  1. 上面的flags一般复制为0 .

socket模型创建流程图:

在这里插入图片描述
服务端代码:

/******创建套接字******/
int listenfd  = socket(AF_INET, SOCK_STREAM, 0);

/*****绑定本地ip和端口*******/
struct sockaddr_in serv;

//初始化serv
memset(serv,0, sizeof(serv));
//确定为ipv4
serv.sin_family = AF_INET;
//端口,把本地字节序转换为网络字节序
serv.port = htons(port); 

/*将serv的ip设置为 INADDR_ANY,接受任意的ip的客户端发来的数据。htonl将本地字节序转换为网络字节序
*/
serv.sin_addr.s_addr = htonl(INADDR_ANY);

//绑定
bind(listenfd,(struct sockaddr*)&serv,sizeof(serv));

//设置监听
listen(listenfd, 32);


/**************开始连接*************/
//用sockaddr_in 保存客户端的信息
sockaddr_in clie;
while(1){
	socklen_t cliaddr_len = sizeof(clie);
	connfd = accept(listenfd,(struct sockaddr*)&clie, &cliaddr_len);
	
	//接受前端传来的数据
	char buff[1024];
	//str用于保存转换后的ip地址
	char str[1024] = { 0 };
	printf("received from %s at port %d\n",
		inet_ntop(AF_INET,&clie.sin_addr,str,sizeof(str)ntohs(clie.sin_port));
	
	//对于buff操作,do something

	//用write把buf重新操作后的数据返回给客户端
	write(connfd, buf ,n);
	close(connfd);
}

客户端代码:

//创建socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

//保存服务端的IP和端口信息
memset(&servaddr, 0 , sizeof(servaddr));
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
//本地服务器,并转换为相应的字节序
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);

//connect
connect(sockfd,(struct sockaddr*)&servaddr, sizeof(servaddr));

//向服务器发送数据
while(1){
	char buf[1024];
	//从输入流中接受数据
	fgets(buf, sizeof(buf), stdin);
	//向服务器发送数据
	write(sockfd, buf , strlen(buf));
	
	//接受服务器的数据
	read(sockfd, buf , sizeof(buf));

	//对buf的结果打印
}
close(sockfd);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值