Linux网络编程之Tcp(内含服务器、客户端代码实例)

前言:

本节讲解需要相关的网络基础知识,如果缺少相关知识,请先学习:Linux网络编程之网络基础Linux网络编程之网络基础2

Tcp模型:

先打开我们之前讲过的Tcp模型作为参考:

img点击并拖拽以移动

服务器端:

创建socket:int socket(int domain, int type, int protocal);

参数1:域 AF_INET(ipv4) AF_INET6 (ipv6)

参数2:类型 SOCK_DGRAM(udp协议) SOCK_STREAM (tcp协议)

参数3:默认0即可

绑定地址:int bind(int sockfd, const struct sockaddr* addr, socklen_t len);

参数1:socket描述符

参数2:地址结构体

​ //通用的地址【此处所用的结构体】
struct sockaddr{
sa_family_t sa_family; //协议族
char sa_data[14]; //地址
}
//ipv4地址【ipv4专用,我们平常所用的最多】
struct sockaddr_in{
short int sin_family; //协议族
unsigned short int sin_port; //端口号
struct in_addr sin_addr; // IP地址【结构体原型在下面】
unsigned char sin_zero[8]; //填充
}
struct in_addr{
unsigned long s_addr; // IP地址 4字节整数
}

补充1:字符串形式的IP地址与整数形式的IP地址转化

从上面可以看到,我们用的地址是整数型的;而我们平常在现实生活中所看到的地址:例如:192.168.1.1是字符串型的;

地址转化函数:

in_addr_t inet_addr(const char* cp); //将192.168.1.1转化为整数型的IP地址(网络字节序)

举例:in_addr.saddr = inet_addr(“192.168.1.1” );

char *inet_ntoa (struct in_addr) //将整数形式的IP地址转化为字符串形式的IP地址

补充2:网络字节序

补充2.1:大端和小端模式

要想知道网络字节序是什么?首先需要知道大端和小端模式;简而言之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中 ;小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中 ;

具体知识请参考https://blog.csdn.net/litter_driver777/article/details/51636311。

我们自己电脑可能是大端,也可能是小端的;同样,别人的电脑也有可能是大端或者小端的,所以在网络上传输数据时,我们就需要统一他们的大小端模式。

规定网络中传输的是大端模式,所以网络字节序是大端模式的;

主机字节序和网络字节序转化函数:

uint32_t htonl(uint32_t hostlong); //将32位的数据从主机字节序转换为网络字节序

​ //举例: in_addr.saddr = htonl(INADDR_ANY)

uint16_t htons(uint16_t hostshort); //将16位的数据从主机字节序转换为网络字节序

uint32_t ntohl(uint32_t netlong); //将32位的数据从网络字节序转换为主机字节序

uint16_t ntohs(uint16_t netshort); //将16位的数据从网络字节序转换为主机字节序

监听:int listen(int sockfd, int backlog);

参数1:socket描述符

参数2:backlog 允许连接的客户机的数目

等待连接:int accept(int sockfd, struct sockaddr* reStrict addr, socklen_t* restrict len);

参数1:socket描述符

参数2:客户机的地址(接收到的)

参数3:地址长度的指针(注意:是指针哦,不是整形)

返回值:新的套接字的fd(记住了:以后收发用这个新的sockfd哦!)

发送:ssize_t send(int sockfd, const void* buf, size_t nbytes, int flags);

参数1:新的套接字的fd(accept的返回值)

参数2:要发送的数据

参数3:数据的长度

参数4:默认为0即可

接收:ssize_t recv(int sockfd, void* buf, size_t nbytes, int flags);

关闭连接close():

客户机端:

连接服务器:connect(int sockfd, const struct sockaddr* addr, socklen_t len);

参数1:socket描述符

参数2:要连接的服务器的地址

参数3:地址长度—整形

其余函数参考服务器端的讲解。

代码:

服务器code:

#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>

#define portnum 3333

int main()
{
	int sockfd;
	int new_fd;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	char buffer[128];
	int nByte;
	int sin_size;
	
	//1.创建套接字
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("create socket error!\n");
		exit(1);
	}
	
	//2.1设置要绑定的地址
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(portnum); //字节序(大小端)
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
		
	//2.绑定地址
	bind(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr));
	
	//3.监听端口
	listen(sockfd,5);
		
	while(1)
	{
		//4.等待连接
		sin_size = sizeof(struct sockaddr);
		new_fd = accept(sockfd,(struct sockaddr*)(&client_addr),&sin_size);//注意:第3个参数为socklen_t*(整形的指针)
		printf("server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); //将整数型的IP地址转化为字符型(192.168.1.1)
		
		//5.接收数据
		nByte = recv(new_fd, buffer, 128, 0);
		buffer[nByte] = '\0';
		printf("server reciivd : %s\n", buffer);
		
		//6.结束连接
		close(new_fd);
	}	
	
	close(sockfd);
	
	return 0;
	
}	

客户端code:

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define portnum 3333

int main()
{
	struct sockaddr_in server_addr;
	char buffer[128];
	
	//1.创建套接字
	int sockfd;
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("create socket error!\n");
		exit(1);
	}
	
	//2.1设置要连接的服务器的地址
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(portnum);
	server_addr.sin_addr.s_addr = inet_addr("192.168.103.100");
	
	//2.连接服务器
	if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr)) == -1)
	{
		printf("connect error\n");
		exit(1);
	}
	
	//3.发送数据到服务器
	printf("please input char:\n");
	fgets(buffer,128,stdin);
	send(sockfd, buffer, strlen(buffer), 0);
	
	//4.关闭连接
	close(sockfd);
	
	return 0;
	
}

运行结果:

操作流程:先开服务器,再开客户端,客户端提示输入please input char:后,自行输入任意字符串,点enter后发送,可以看到服务器收到了数据。

服务器端:

在这里插入图片描述

客户机端:

在这里插入图片描述

结束

猜你喜欢

转载自blog.csdn.net/QQ1402369668/article/details/86090092