【网络】TCP的网络编程流程

       TCP作为面向连接的,可靠的,面向字节流的协议。TCP的两端进行通信时,首先必须进行两端的连接,这篇就来详细介绍TCP的连接,在网络中的编程流程。

        通讯的两端:数据提供者(服务器)    数据获取者(客户端)soket编程

        在linux下,基于TCP的C/S模式,客户端和服务器之间是如何建立连接并且进行通讯的呢?这里我们就涉及到网络编程的内容,客户端一般作为为主动发起连接方也就是请求方,而服务器则是作为被动链接方也就是响应请求方。

目录

一、服务器端:被动链接方  IP地址+端口号

二、客户端:主动连接方,IP+port

三、示例代码


一、服务器端:被动链接方  IP地址+端口号

(1)Int listenfd(单个地址,只记录服务器) = socket(int domain,int type,int protocol);//返回文件描述符,打开网络,给外部提供连接   接收连接的套接字

                   Domain: 协议族AF_INET  IPv4协议

                   Type:选择的协议tcp:SOCK_STREAM 流式服务

                                                   Udp: SOCK_DGRAM  数据报服务

                   Protocol:type底下的更具体地协议  通常给0

(2)Int Bind(int socketfd,const struct sockaddr *addr,socklen_t  addrlen);//将服务器的IP地址+端口号与listenfd绑定;设置

Struct sockaddr_in

{                                          

         Int sin_family;//地址簇 IPV4 PF_INET == AF_INET

         Short sin_port;//端口号整型值 系统预留:0-1024 预留:1025-5000 5000以上

         Struct in_addr sin_addr;//IP地址

}

Struct in_addr

{

         U_int32_t s_addr;//32位无符号

}

端口号转换:htons(short port);

地址转化函数:int_addr_t inet_addr(const char* strptr);                      

         (3)Listen(int listenfd,int size);//内核启动监听,接收客户端链接(面向连接);并不会阻塞;

真正做监听工作的是内核;

Size:监听大小

         早期为监听队列的大小;

         现在是维护了两个队列:已完成链接的队列;size+1

         正在完成链接的队列;

         Listenfd:套接字

         (4)Int c (地址对,具体与服务器连接上的客户端)= accept(int listenfd,struct sockaddr* cliaddr(客户端),int *len);//获取一个链接完成的客户端;提供服务

C:返回维护本次连接的文件描述符;

(5)服务于c:

                   接收数据:recv(int c, void* buff, int buffsize, int flag);//4个参数

                   发送数据:send(int c,void* buff, int datasize, int flag);//4个参数

         断开连接Close(c);//关闭客户端            

二、客户端:主动连接方,IP+port

                  (1)Int sockfd = socket(int domain,int type,int protocol);

                   (2)Int Bind(int socketfd,const struct sockaddr *addr,socklen_t  addrlen);//可选  如果没有绑定,内核也会自动选择一个可用的端口号,自动探测本地的ip地址

Struct sockaddr_in

{                                          

         Int sin_family;//地址簇 IPV4 PF_INET == AF_INET

         Short sin_port;//端口号整型值 系统预留:0-1024 预留:1025-5000 5000以上

         Struct in_addr sin_addr;//IP地址

}

Struct in_addr

{

         U_int32_t s_addr;//32位无符号

}

端口号转换:htons(short port);

地址转化函数:int_addr_t inet_addr(const char* strptr);           

             (3)Connet (int sockfd,struct sockaddr * serv_addr,int addrlen);//发起连接,与服务器完成链接

             (4)recv(int c, void* buff, int buffsize, int flag);//4个参数

                   send(int c,void* buff, int datasize, int flag);//4个参数

                   Close(c);  

三、示例代码

下面的示例代码主要是进行服务器和客户端的连接,在连接成功后,两端进行简单的数据交互。

//服务器端
#include
#include
#include
#include
#include
#include
#include
#include
#include
int listenfd = -1;
void sigfun(int sign)
{
	close(listenfd);
	exit(0);
}
int main()
{
	signal(SIGINT,sigfun);
	//                     协议族   TCP协议 
	int listenfd = socket(AF_INET,SOCK_STREAM,0);
	assert(listenfd != -1);

	struct sockaddr_in ser,cli;
	memset(&ser,0,sizeof(ser));

	ser.sin_family = AF_INET;//地址簇
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");//ip地址
	ser.sin_port = htons(6000);//端口号

	
	int res = bind(listenfd,(struct sockaddr*)&ser,sizeof(ser));//绑定
	assert(res != -1);//绑定失败:1.ip地址不对 2.端口号被占用或者没有权限用

	listen(listenfd,5);//size = 5,内核维护的已完成链接的客户端的文件描述符个数(6)
	while(1)//服务器接受不同客户端链接
	{
		int clilen = sizeof(cli);
		//                        记录客户端的地址信息
		int c = accept(listenfd,(struct sockaddr *)&cli,&clilen); 	
		assert(c != -1);

		while(1)//与一个客户端交互的循环
		{
			char buff[128] = {0};
			int n = recv(c,buff,127,0);//默认阻塞运行
			//两次出错:recv()函数本身出错;c不存在即就是客户端主动关闭
			if(n <= 0)
			{
				printf("one client unlink\n");
				close(c);
				break;
			}
			printf("%d,%s\n",c,buff);

			send(c,"OK",2,0);//发送
		}
	}
	close(listenfd);
}
//客户端
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
	int sockfd = socket(AF_INET,SOCK_STREAM,0);
						//协议族
	assert(sockfd != -1);

	struct sockaddr_in ser;
	memset(&ser,0,sizeof(ser));

	ser.sin_family = AF_INET;//地址族
	ser.sin_port = htons(6000);
	ser.sin_addr.s_addr = inet_addr("127.0.0.1");

	int res = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));
	assert(res != -1);

	while(1)
	{
		printf("please input:");
		char buff[128] = {0};
		fgets(buff,128,stdin);
		if(strncmp(buff,"end",3) == 0)
		{
			close(sockfd);
			break;
		}
		send(sockfd,buff,strlen(buff)-1,0);
		char recvbuff[128] = {0};
		int n = recv(sockfd,recvbuff,127,0);
		if(n<=0)
		{
			close(sockfd);
			break;
		}
		printf("clien recv data :%s\n",recvbuff);
	}
}

这两端数据交互的运行结果如下:

【网络】TCP的网络编程流程_第1张图片

总结:

1.tcp的编程流程,明白通信的两端

2.服务器端的编程流程

3.客户端的编程流程

4.简单的代码展示

你可能感兴趣的:(计算机网络)