IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Linux网络编程之TCP编程 -> 正文阅读

[网络协议]Linux网络编程之TCP编程

学习目标:

  • 1、编写TCP多线程服务器

  • 2、编写TCP多进程并发服务器

网络编程基础:

TCP:(Transfer Control protocol,传输控制协议)提供面向连接的,一对一的可靠传输的协议

数据无误,数据不丢失,数据无失序

适用场景:

适合对传输质量要求较高,以及传输大量数据的通信

在需要可靠数据传输的场合,通常适用TCP协议

MSN/QQ等即时通讯软件的用户登录账号管理相关的功能通常采用TCP协议

UDP:(user Datagram Protocol,用户数据报协议):提供不可靠,无连接的传输协议

适用场景发送小尺寸数据(如对DNS服务器进行IP地址查询时) 在接收数据,给出应答较困难的网络中适用UDP(如无线网络) 适合于广播/组播式通信中 MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通常采用UDP协议 流媒体,VOD,VoIP,IPTV等网络多媒体服务中通常采用UDP方式进行实时数据传输

字节转换函数:

主机字节序到网络字节序:

????????????????????????u_long htonl(u_long hostlong);

????????????????????????u_short htons(u_short short);

网络字节序到主机字节序:

????????????????????????u_long ntohl(u_long hostlong);

????????????????????????u_short ntohs(u_short short);

IP地址的转换:

inet_aton()

????????将strptr所指的字符串转换成32位的网络字节序二进制值

inet_addr()

????????功能同上,返回转换后的地址

????????仅适用于IPV4,出错时返回-1。

????????局限性:不能用于255.255.255.255的转换

inet_ntoa()将32位网络字节序二进制地址转换成点分十进制的字符串

inet_pton()

????????int inet_pton(int af, const char* src ,void* dst)

????????将IPV4/IPV6 的地址转换成binary格式

????????使用于IPV4/IPV6

????????能正确处理255.255.255.255的转换问题

参数:

????????1.地址协议族(AF_INET或AF_INET6)

????????2.src:是一个指针(填写分点形式的IP地址(主要指IPV4))

? ? ? ? 3.dst:转换的结果给到dst

inet_ntop(int af,const void *src,char *dst,socklen_t size)

????????把ipv4和ipv6的网络字节序变成本地的字符串形式的IP地址

参数:

????????1.af:地址协议族(AF_INET或AF_INET6)

????????2.src:是一个指针(32)

????????3.dst:输出结果为32位点分形式的IP地址

????????4.size:长度

熟悉TCP编程API

1.socket函数

int socket(int domain,int type,int protocol);

参数

domain:

????????????????AF_INET

????????????????AF_INET6

????????????????AF_UNIX,AF_LOCAL

????????????????AF_NETLINK

????????????????AF_PACKET

type:

????????SOCK_STREAM: 流式套接字,唯一对应于TCP

????????SOCK_DGRAM:数据报套接字,唯一对应着UDPSOCK_RAW:原始套接字

protocol:

????????????????一般填0,原始套接字编程时需填充

返回值:

????????成功返回文件描述符

????????出错返回-1

如果是IPV6编程,要使用struct sockddr_in6结构体(man 7 IPV6),通常使用struct sockaddr_storage来编程。

2.bind函数

int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)

参数:

????????sockfd:通过socket()函数拿到的fd

????????addr:采用struct sockaddr的结构体地址,通用结构体

????????struct sockaddr{

????????sa_family_t sa_family;

????????char sa_data[4];

????????}

// 基于Internel通信结构体

????????struct sockaddr_in{

????????as_family_t sin_family;

????????in_port_t sin_port;

????????struct in_addr sin_addr;

????????sin_zero , //填充字节,需清零

????????}

????????struct in_addr{

????????uint32_t s_addr;

????????}

????????addrlen:地址长度

3.listen()函数

int listen(int sockfd,int backlog);

参数:

????????sockfd: 通过socket()函数拿到的fd;

????????backLog:同时允许几路客户端和服务器进行正在连接的过程(正在三次握手),一般填5

????????内核中服务器的套接字fd会维护2个链表

1.正在三次握手的客户端链表(数量=2*backlog+1)

2.已经建立好连接的客户端链表(已经完成三次握手分配好了的newfd)

返回值:

????????成功返回0;? ?出错返回-1

listen(fd,5);//表示系统允许11(2*5+1)个客户端同时进行三次握手

4.accept()函数

阻塞等待客户端连接请求

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数:

????????sockfd:经过前面socket()创建并通过bind(),listen()设置过的fd

????????addr:指向存放地址信息的结构体的首地址

????????获取客户端IP地址和端口号

????????addrlen:存放地址信息的结构体的大小

返回值:

????????成功,返回返回已经建立连接的新的newfd

????????出错,返回-1

5.客户端连接函数connect()

int connect (int sockfd, struct sockaddr * serv_addr, int addrlen)

参数:

????????sockfd:通过socket()函数拿到的fd

????????addr:struct sockaddr的结构体变量地址

????????addrlen:地址长度

返回值:

????????????????成功,返回0

????????????????失败,返回-1

TCP编程基本流程:

TCP实现并发服务器的基本流程:

TCP实现多进程并发服务器

服务端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<signal.h>
#include<sys/wait.h>
#define BUFSIZE   1024
#define  QUIT_STR "QUIT"
#define SERV_IP 5001
#define SERV_IP_ADDR  "192.168.224.132"
#define  BACKLOG  5


void *client_data_handle( void *arg)
{
	//强转为int型的指针,对它再取值
	int newfd=*(int *) arg;
	int ret = -1;
	char buf[BUFSIZE];
	printf(" child handle  progess : newfd =%d\n",newfd);
	while(1)
	{
		
		do
		{
			bzero(buf,BUFSIZE);
			ret=read(newfd,buf,BUFSIZE-1);
		}while(ret < 1);
		if ( ! ret)
		{
			break;
		}
		printf(" recevice data :%s\n",buf);
		//两个字符串做比较,不一样返回0,一样返回1,则执行下面的内容
		if( ! strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))	             		          {
			printf(" Client is exiting !\n");
			break;
		}
		
	}
	close(newfd);
	return NULL;
}


void child_data_handle(int signum)
{
	if( SIGCHLD  == signum)
	{
		waitpid(-1,NULL,WNOHANG);
	}
}
int main()
{
	printf(" this is service!\n");
	int fd = -1;
	signal(SIGCHLD,child_data_handle);
	struct sockaddr_in sin;
	//1.socket
	fd=socket(AF_INET,SOCK_STREAM,0);
	
	if( fd <0)
	{

		perror("socket");
		exit(1);
	}
	//把结构体清零
	bzero(&sin,sizeof(sin));
	sin.sin_family=AF_INET;

	sin.sin_port=htons(SERV_IP);//两个字节
/*
inet_addr(),返回转换后的地址,仅适用于IPV4,出错时返回-1
将IPV4/IPV6 的地址转换成binary格式
inet_pton(AF_INET,SERV_IP_ADDR ,(void*) sin.sin_addr.s_addr);
两种方法都可以
*/

	sin.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);
	//优化,可以在任何的服务器中运行,自动获取当前的ip地址
	//sin.sin_addr.s_addr=INADDR_ANY;
	//2.bind
	if(bind(fd,(struct sockaddr *)&sin,sizeof(sin))<0)
	{
		perror("bind");
		exit(1);
	}
	//3.listen
      if(listen(fd,BACKLOG)<0)
	{
		perror("listen");
		exit(1);
	}
	//4.acccept

//进程
	int newfd =  -1;
	pid_t  pid;
	struct sockaddr_in cin;
	socklen_t  addrlen =sizeof(cin);
	while(1)
	{
		 newfd=accept(fd,NULL,NULL);
		if( newfd <0)
		{
			perror("acccept");
			exit(1);
		}
	pid =fork();
	if( pid <0)
	{
		perror("fork");
		break;
	}
	if ( pid == 0)
	{
		char  ipv4_addr[16];
	     if(! inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
	{
		perror("inet_ntop");
		exit(1);
	}
	//获取端口号和ip地址
	printf("client : (%s , %d) is connect !\n", ipv4_addr,ntohs(cin.sin_port));
	
	client_data_handle(&newfd);
	close(fd);
	}
	if( pid > 0)
	{
		close(newfd);
	}
		
	}
		close(fd);
			
	return  0;

}

客户端:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#define BUFSIZE   1024
#define  QUIT_STR "QUIT"
#define SERV_PORT 5001
#define SERV_IP_ADDR  "192.168.224.132"
int main(int argc , char **argv)
{
	

	int fd = -1;
	if( argc != 3)
	{
		exit(1);
	}
	int port = -1;
	port=atoi(argv[2]);
	struct sockaddr_in sin;
	//1.socket
	fd=socket(AF_INET,SOCK_STREAM,0);
	
	if( fd <0)
	{
		perror("socket");
		exit(1);
	}
	//把结构体清零
	bzero(&sin,sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=htons(port);
	sin.sin_addr.s_addr=inet_addr(argv[1]);

	if(connect(fd,(struct sockaddr *)&sin,sizeof(sin)) < 0)
	{
		perror("connect");
		exit(1);
	}
	char buf[BUFSIZE];
	while(1)
	{
		bzero(buf,BUFSIZE);
		if(fgets(buf ,BUFSIZE-1,stdin) == NULL)
		{
			continue;
		}
		write(fd,buf,strlen(buf));
	if( !strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))	
		{
			
			break;
		}

	}
		return 0;
}

实现效果:

TCP实现多线程并发服务器:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<signal.h>
#include<sys/wait.h>
#define BUFSIZE   1024
#define  QUIT_STR "QUIT"
#define SERV_IP 5001
#define SERV_IP_ADDR  "192.168.224.132"
#define  BACKLOG  5

void *client_data_handle( void *arg)
{
	//强转为int型的指针,对它再取值
	int newfd=*(int *) arg;
	int ret = -1;
	char buf[BUFSIZE];
	printf(" pthread  progess : newfd =%d\n",newfd);
	while(1)
	{
		
		do
		{
			bzero(buf,BUFSIZE);
			ret=read(newfd,buf,BUFSIZE-1);
		}while(ret < 1);
		if(ret < 0)
		{
			exit(1);
		}
		if ( ! ret)
		{
			break;
		}
		printf(" recevice data :%s\n",buf);
		//两个字符串做比较
		if( ! strncasecmp(buf,QUIT_STR,strlen(QUIT_STR)))	             		          {
			printf(" Client is exiting !\n");
			break;
		}
		
	}
	close(newfd);
	return NULL;
}

void child_data_handle(int signum)
{
	if( SIGCHLD  == signum)
	{
		waitpid(-1,NULL,WNOHANG);
	}
}
int main()
{
	printf(" this is service!\n");
	int fd = -1;
	signal(SIGCHLD,child_data_handle);
	struct sockaddr_in sin;
	//1.socket
	fd=socket(AF_INET,SOCK_STREAM,0);
	
	if( fd <0)
	{

		perror("socket");
		exit(1);
	}
	//把结构体清零
	bzero(&sin,sizeof(sin));
	sin.sin_family=AF_INET;

	sin.sin_port=htons(SERV_IP);//两个字节

	sin.sin_addr.s_addr=inet_addr(SERV_IP_ADDR);
	//优化,可以在任何的服务器中运行,自动获取当前的ip地址
	//sin.sin_addr.s_addr=INADDR_ANY;
	//2.bind
	if(bind(fd,(struct sockaddr *)&sin,sizeof(sin))<0)
	{
		perror("bind");
		exit(1);
	}
	//3.listen
      if(listen(fd,BACKLOG)<0)
	{
		perror("listen");
		exit(1);
	}
	//4.acccept
	/*
	int newfd =  -1;
           newfd=accept(fd,NULL,NULL);
	if( newfd <0)
	{
		perror("acccept");
		exit(1);
	}
	*/
	//优化,服务端知道哪个客户端连接了,并可以获取端口号和ip地址
	/*
	每接收一个就打印它的客户信息,并创建一个线程,并跳转到线程这个函数里面去
	*/
	
	int newfd =  -1;
	pthread_t  tid;
	struct sockaddr_in cin;
	socklen_t  addrlen =sizeof(cin);
	while(1)
	{
	newfd=accept(fd,(struct sockaddr *)&cin,&addrlen);
	         if( newfd <0)
                {
                        perror("acccept");
                        exit(1);
                }

	char  ipv4_addr[16];
	if(! inet_ntop(AF_INET,(void *)&cin.sin_addr,ipv4_addr,sizeof(cin)))
	{
		perror("inet_ntop");
		exit(1);
	}
	//获取端口号和ip地址
	printf("client : (%s , %d) is connect !\n", ipv4_addr,ntohs(cin.sin_port));
	pthread_create(&tid,NULL,client_data_handle,(void *)&newfd);
	}	
	close(fd);			
	return  0;

}

服务端和TCP实现多进程并发服务器的服务端代码一致

实现效果:

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 21:27:49  更:2022-09-24 21:29:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 13:43:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码