TCP

TCP

TCP协议可靠性

TCP协议传输数据时会为每个字节分配一个序列号,通过这个序列号就可以判断数据是否重复到达以及数据是否丢失,还可以通过序列号对数据进行排序。另外,接收端每次接收到数据之后必须发送确认应答(ACK),如果在超时时间内没有发送应答信号(ACK),则TCP协议会认为数据没有送达,则会重新发送数据。

TCP协议判断数据是否损坏的方式是给每个数据段都添加校验和,接收端收到数据段进行校验,如果校验失败则丢弃已经损坏的数据段,也并不会进行确认应答,所以TCP协议会再次传输数据段。

因为通信可能是建立在不可靠的网络中以及网络层不可靠的传输机制,所以TCP协议中采用了一种*基于时钟的序列号握手机制*实现双方的有效连接,避免出现错误的连接初始化。

image

image

练习:主机A作为服务器,主机B作为客户端,主机A和主机B建立TCP连接,主机B可以向主机A发送消息

主机A



#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
 #include <unistd.h>
//TCP服务器代码   ./xxx   port


int main(int argc, char const *argv[])
{
	//1.创建TCP套接字
	int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (tcp_socket == -1)
	{
		fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	//2.绑定自身的IP地址和端口
	struct sockaddr_in  host_addr;

	host_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	host_addr.sin_port   		= htons(atoi(argv[1]));			//目标端口,必须转换为网络字节序
	host_addr.sin_addr.s_addr   = htonl(INADDR_ANY);		    //目标地址  INADDR_ANY 这个宏是一个整数,所以需要使用htonl转换为网络字节序

	bind(tcp_socket,(struct sockaddr *)&host_addr, sizeof(host_addr));

	//3.设置监听  队列最大容量是5
	listen(tcp_socket,5);

	//4.等待接受客户端的连接请求
	struct sockaddr_in  client;
	socklen_t client_len = sizeof(client);

	int connect_fd = accept(tcp_socket,(struct sockaddr *)&client,&client_len); //会阻塞
	char buf[128] = {0};

	//5.说明双方建立连接,此时可以接收数据
	while(1)
	{
		
		
		read(connect_fd,buf,sizeof(buf));
		printf("recv from [%s],data is = %s\n", inet_ntoa(client.sin_addr) ,buf);
		bzero(buf,sizeof(buf));
	}


	return 0;
}

主机B(客户端)




#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
 #include <unistd.h>
//TCP客户端代码   ./xxx   port  IP


int main(int argc, char const *argv[])
{
	//1.创建TCP套接字
	int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (tcp_socket == -1)
	{
		fprintf(stderr, "tcp socket error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}

	
	//2.发起连接请求,等待接受服务器接受连接
	struct sockaddr_in  dest_addr;
	dest_addr.sin_family 		= AF_INET; 						//协议族,是固定的
	dest_addr.sin_port   		= htons(atoi(argv[1]));			//服务器端口,必须转换为网络字节序
	dest_addr.sin_addr.s_addr   = inet_addr(argv[2]);			//服务器地址 "192.168.64.xxx"  


	int ret = connect(tcp_socket,(struct sockaddr *)&dest_addr,sizeof(dest_addr));
	if (ret < 0)
	{
		fprintf(stderr, "connect error,errno:%d,%s\n",errno,strerror(errno));
		exit(1);
	}
	char buf[128] = {0};

	//3.说明双方建立连接,此时可以接收数据
	while(1)
	{
		printf("请输入:");
		scanf("%s",buf);
		write(tcp_socket,buf,sizeof(buf));
		bzero(buf,128);
	}


	return 0;
}
posted @ 2025-05-13 21:18  骗人就变小狗  阅读(330)  评论(0)    收藏  举报