TCP 服务器/客户端(实现下载)
TCP/IP :
TCP/IP:在网络通信中,TCP/IP是主流协议()
应用层:用户自定义的协议(HTTP,EMAIL,),用于用户之间数据的传送
传输层:(传输控制:TCP,UDP)负责点对点之间连接建立,传输控制协议的指定()
网络层:用于查找路由(查找)
网络接口层 : 将二进制转换为数据帧。
TCP帧:
[源端号][目的端口]
[ 顺序号 ]
[TCP包头长][URG/ACK/PSH/RST/SYN/FIN][窗口大小]
[检验和][紧急指针]
[可选项 ]
[数据包]
TCP:面向连接,安全可靠有状态的传输协议。(比UDP效率差)
怎样连接:三次握手简述(确保双方一定同时在线)
A与B建立TCP连接时:首先A向B发SYN(同步请求)
然后B回复SYN+ACK(同步请求应答)
最后A回复ACK确认
这样TCP的一次连接(三次握手)的过程就建立了!
/**** 下面部分转载自 : 简述TCP的三次握手过程_戴耳机的皮皮熊的博客-CSDN博客_tcp三次握手
TCP握手协议详述 :
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接.
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
SYN:同步序列编号(Synchronize Sequence Numbers)
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手.
完成三次握手,客户端与服务器开始传送数据
所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:
(1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。 (2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。 (3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
SYN攻击:
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:
#netstat -nap | grep SYN_RECV
上面转载到此处结束 ****/
TCP通信:
服务器:
1、创建套接字(打开设备)
socket
2、绑定
bind
3、监听:(设置最大的可连接的线路的数量)
listen
4、等待连接:是一个阻塞函数(注:执行一该函数,则连接一次)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回一个套接字,用于在此套接字上收发消息
5、收到消息
recv
6、关闭套接字 注:由于accept和recv都需要阻塞等待,accept返回新的连接描述符。
为每一个新的连接请求分配一个新的进程或线程
客户端:
1、创建套接字(打开设备)
2、绑定套接字
3、发出连接请求
connect
4、收发消息
send
recv
5、关闭请求
close
传输层:UPD报文SOCK_DGRAM TCP:流式套接字SOCK_STREAM
注:由于套接字上绑定有端口号,为了防止复用端口号,套接字默认不允许复用。
API:设备套接字 ----> setsockopt ( int sock,int level ) ; level:SOL_SOCKET 对套接字进行设置 socklen_t len=1 ;
if ( setsockopt ( sock,SOL_SOCKET,SO_REUSEADDR,&len,sizeof(len) ) <0 )
{
perror ( "setsocket fail" ) ;
return -1 ;
}
TCP 服务器的代码实现 :
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>
//创建锁
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//子线程:接收链路信息
void* threadfun(void* arg)
{int sock=*(int*)arg;
//解锁pthread_mutex_unlock(&mutex);
//接收消息char buf[100]="";int ilen=0;while(1){ilen=recv(sock,buf,99,0);if(ilen<=0)break;buf[ilen]='\0';printf("收到:%s\n",buf);}close(sock);
}
//TCP:流式套接字
int main()
{
//1创建套接字---打开设备int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket fail");return -1;}
//修改套接字的网络层:允许IP复用socklen_t len=1;if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&len,sizeof(len))<0){perror("setsocket fail");return -1;}
//2填充结构体并绑定struct sockaddr_in myaddr; //7979;memset(&myaddr,0,sizeof(myaddr));myaddr.sin_family =AF_INET;myaddr.sin_port =htons(7979);myaddr.sin_addr.s_addr =INADDR_ANY;if(bind(sock,(struct sockaddr*)&myaddr,sizeof(myaddr))==-1){perror("bind fail");return -1;}
//3监听:设置最大的可连接数量,并监听listen(sock,44);
//4等待连接 acceptint newsock=-1;pthread_t tid;while(1){//上锁pthread_mutex_lock(&mutex);newsock=accept(sock,NULL,NULL);if(-1==newsock)break;//创建线程--函数pthread_create(&tid,NULL,threadfun,&newsock);//cout<<"有人连接我了\n"<<endl;}
/*
//5等待该链路上消息到来char buf[100]="";recv(newsock,buf,99,0);printf("收到:%s\n",buf);
*/
//6关闭close(sock);return 0;
}
TCP 客户端的代码实现 :
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
int main()
{
//1创建套接字int sock=socket(AF_INET,SOCK_STREAM,0); //SOCK_STREAM 流氏sock
//2[绑定:系统为该套接字默认绑定一个空的端口号和一个网卡地址]
//3主动发出连接请求/*填充连接服务器的IP信息*/struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr)); //填充为0saddr.sin_family =AF_INET;saddr.sin_port =htons(7979);saddr.sin_addr.s_addr =inet_addr("192.168.8.209");if(connect(sock,(struct sockaddr*)&saddr,sizeof(saddr))<0) //连接{perror("connect fail");return -1;}
//4收发消息char buf[100]="";while(1){scanf("%s",buf); //客户端可以连续的发送内容send(sock,buf,strlen(buf),0);//strlen 求字符串的长度}
//5关闭close(sock);
}
TCP 的服务器 , 实现从客户端发送信息到服务器 , 服务器接收到文件名后 , 将服务器的文件发送给客户端 , 从而实现客户端下载服务器的内容 , 如下服务器代码 :
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>#include<fcntl.h>
//创建锁
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//子线程:接收链路信息
void* threadfun(void* arg)
{int sock=*(int*)arg;
//解锁pthread_mutex_unlock(&mutex);
//接收消息char buf[100]="";int ilen=0;while(1){char ch[100]="";char chr[1024]="";ilen=recv(sock,buf,99,0);if(ilen<=0)break;buf[ilen]='\0';printf("即将copy文件名%s:",buf); //buf的内容为客户端发送过来的文件名int fdr=open(buf,O_RDONLY);if(-1==fdr){perror("fail:");return ;}while((ilen=read(fdr,chr,1024))>0) //将文件读取到 chr[1024] 中{send(sock,chr,strlen(chr),0); //发送内容给客户端}}close(sock);
}
//TCP:流式套接字
int main()
{
//1创建套接字---打开设备int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket fail");return -1;}
//修改套接字的网络层:允许IP复用socklen_t len=1;if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&len,sizeof(len))<0){perror("setsocket fail");return -1;}
//2填充结构体并绑定struct sockaddr_in myaddr; //7979;memset(&myaddr,0,sizeof(myaddr));myaddr.sin_family =AF_INET;myaddr.sin_port =htons(7979);myaddr.sin_addr.s_addr =INADDR_ANY;if(bind(sock,(struct sockaddr*)&myaddr,sizeof(myaddr))==-1){perror("bind fail");return -1;}
//3监听:设置最大的可连接数量,并监听listen(sock,44);
//4等待连接 acceptint newsock=-1;pthread_t tid;while(1){//上锁pthread_mutex_lock(&mutex);newsock=accept(sock,NULL,NULL);if(-1==newsock)break;//创建线程--函数pthread_create(&tid,NULL,threadfun,&newsock);//cout<<"有人连接我了\n"<<endl;}
/*
//5等待该链路上消息到来char buf[100]="";recv(newsock,buf,99,0);printf("收到:%s\n",buf);
*/
//6关闭close(sock);return 0;
}
客户端的实现 :
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<string.h>
#include<fcntl.h>
int main()
{
//1创建套接字int sock=socket(AF_INET,SOCK_STREAM,0);
//2[绑定:系统为该套接字默认绑定一个空的端口号和一个网卡地址]
//3主动发出连接请求/*填充连接服务器的IP信息*///int pid=fork();char buf[100]="";//if(pid>0)//{struct sockaddr_in saddr;memset(&saddr,0,sizeof(saddr)); //填充为0saddr.sin_family =AF_INET;saddr.sin_port =htons(7979);saddr.sin_addr.s_addr =inet_addr("192.168.8.209");if(connect(sock,(struct sockaddr*)&saddr,sizeof(saddr))<0){perror("connect fail");return -1;}
//4收发消息while(1){char bbb[100]="";printf("输入需要拷贝的文件:"); //输入服务器的目录下的文件名scanf("%s",bbb);send(sock,bbb,strlen(bbb),0);//strlen 求字符串的长度 , 将文件名发送给服务器break;}int ilen=0;char aaa[100]="";printf("拷贝为:");scanf("%s",aaa); //将需要拷贝的文件名命名为 XXXint fdw=open(aaa,O_WRONLY|O_CREAT|O_TRUNC,0644);while(1){ilen=recv(sock,buf,99,0);if(ilen<=0)break;buf[ilen]='\0';write(fdw,buf,ilen); //写入到文件里面}
//5关闭close(sock);
}
下面是 TCP 的从客户端发送文件名到服务器 , 服务器将文件发送给客户端 , 改进后的代码 , 更加精炼 , 反正比我上面写的好 ,
下面是服务器端的代码 :
#include<stdio.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<string.h>
#include<fcntl.h>
#include<errno.h>
//拷贝文件信息
struct fileMsg
{char path[255]; //文件名int sock; //套接字
};pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//线程函数
void* threadfun(void* arg)
{
//detach线程:当子线程结束,自己在结束之前释放空间,不必需要让父进程来通过join释放pthread_detach(pthread_self());//线程结束,会结束此空间//取出套接字struct fileMsg fm=*(struct fileMsg*)arg;pthread_mutex_unlock(&mutex);
//一边读取文件 一边发送信息char buf[1024]="";int ilen=-1;int fd=open(fm.path,O_RDONLY);if(fd<0){perror("open fail\n");}else{while((ilen=read(fd,buf,1024))>0){if(send(fm.sock,buf,ilen,0)!=ilen)break;}}close(fm.sock);close(fd);
}int main(int argc,char* argv[])
{if(argc<2){perror("arg 不足\n");return -1;}
//判断文件的权限是否存在---读if(access(argv[1],R_OK|F_OK)==-1){fprintf(stderr,"%s %s\n",argv[1],strerror(errno));}//填充结构体:struct fileMsg fm;strcpy(fm.path,argv[1]);int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("sock");return -1;}
//修改套接字的属性--允许复用socklen_t s1=sizeof(socklen_t);if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&s1,sizeof(s1))<0){perror("setsock fail");return -1;}struct sockaddr_in myaddr;bzero(&myaddr,sizeof(myaddr));myaddr.sin_family =AF_INET;myaddr.sin_port =htons(7979);myaddr.sin_addr.s_addr =INADDR_ANY;if(bind(sock,(struct sockaddr*)&myaddr,sizeof(myaddr))<0){perror("bind fail");return -1;}if(listen(sock,44)<0){perror("listen fail");return -1;}int newsock=0;pthread_t tid;while(1){//上锁pthread_mutex_lock(&mutex);newsock=accept(sock,NULL,NULL);if(-1==newsock){break;}//填充结构体fm.sock=newsock;//多位同学连接,创建线程if(0!=pthread_create(&tid,NULL,threadfun,&fm)){//解锁pthread_mutex_unlock(&mutex);//关闭套接字close(newsock);continue;}}close(sock);return 0;
}
客户端的代码 :
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<arpa/inet.h>
#include<fcntl.h>
#include<sys/stat.h>
int main(int argc,char* argv[])
{if(argc<2){perror("参数不足");return -1;}int fd=open(argv[1],O_WRONLY|O_TRUNC|O_CREAT,0644);if(fd<0){perror("open fail");return -1;}int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket fail");}
//发送连接请求--3次struct sockaddr_in saddr;saddr.sin_family =AF_INET;saddr.sin_port =htons(7979);saddr.sin_addr.s_addr =inet_addr("192.168.8.115");if(connect(sock,(struct sockaddr*)&saddr,sizeof(saddr))<0){perror("connect fail\n");return -1;}
//接收int ilen;char buf[1024]="";//从网络上拷贝while((ilen=recv(sock,buf,1024,0))>0){//写入到文件中if(write(fd,buf,ilen)!=ilen){perror("write fail");break;}} close(sock);close(fd);
}
TCP 服务器/客户端(实现下载)相关推荐
- TCP服务器客户端编程流程
TCP服务器客户端编程流程 TCP编程流程 主机字节序列和网络字节序列 套接字地址结构 通用socket地址结构 一般使用会定义一个专用的套接字结构 IP地址转换函数 网络编程接口 TCP服务段代码实 ...
- TCP服务器/客户端实例(C/C )
1.1.Linux下的TCP服务器: #include <stdio.h> #include <stdlib.h> #include <string.h> #inc ...
- Python网络编程之TCP服务器客户端(二)
传输控制协议(官方术语为TCP/IP协议)是互联网的重要组成部分.TCP的第一个版本是在1974年定义的,它建立在网际层协议(IP)提供的数据包传输技术之上.TCP使得应用程序可以使用连续的数据流进行 ...
- 【Chat】实验 -- 实现 C/C++下TCP, 服务器/客户端 多人聊天室
本次实验利用TCP/IP, 语言环境为 C/C++ 利用套接字Socket编程,以及线程处理, 实现Server/CLient 之间多人的聊天系统的基本功能. 结果大致如: 下面贴上代码(参考参考.. ...
- tcp服务器客户端状态图
转载于:https://www.cnblogs.com/rspb/p/4735899.html
- python3.6环境下安装gevent,附协程TCP服务器客户端代码
1.执行 pip3 install gevent 2.报错 importlib._bootstrap' has no attribute 'SourceFileLoader' 3.重新安装pip3 w ...
- 多线程 python tcp 图片_Python第四周之网络编程TCP (服务器/客户端; 线程下载图片;线程版服务器和客户端(单人、多人)) UDP...
# 网络编程 # 计算机网络, 把多台独立自主的计算机,连接到网络,实现资源的共享 # Internet网,(互联网)eniac 1946美国大学第一台电子计算机 # # 一个TCP报文除了包含要传输 ...
- java如何实现tcp传输图像_如何在java中实现TCP服务器和TCP客户端传输文件
我实现了简单的TCP服务器和TCP客户端类,可以从客户端发送消息到服务器,消息将在服务器端转换为大写,但是如何实现从服务器到客户端的传输文件,并从客户端上传文件到服务器.以下代码是我所得到的. TCP ...
- 2022-07-11 Python TCP服务器与客户端
服务器 创建一个服务器代理类TCPServer,其中有init.accept.handle.close函数. 在初始化函数中创建socket对象,绑定主机的地址和端口,并将socket变为一个监听套接 ...
最新文章
- 【Netty】从 BIO、NIO 聊到 Netty
- python数据分析numpy_Python数据分析之numpy学习
- 如何运用UIControl自定义iOS中的控件
- Linux常用网络命令总结
- python udp数据报
- android studio设置Tab为四空格缩进
- 建立数据库的原则(怎样建立一个好的数据库)
- 正方形矩阵求对角线之和
- 【Antlr】Antlr API 简介
- 关于微信开发与微信支付更新
- 如何基于对话框的project基于改变BCG的
- 设计与人工智能设计师
- Pycharm 添加自动表头(包含汉化和英文版本路径)
- leaflet快速渲染聚合矢量瓦片(附源码下载)
- MTK Camera自定义Vendor Tag
- 莱赞多店管家分析Lazada印尼站点热卖商品,商家运营更轻松
- 第二章 Android内核和驱动程序(转)
- 设置 app 不能在模拟器上运行
- suse bios版本_如何检查和更新BIOS版本
- web2.0带来的狂潮
热门文章
- 深圳绿道-观澜段-乡村一号
- vue axios 拦截器配置与封装
- 抖音服务器升级维护中,抖音服务器维护中是什么意思
- python语句print(chr(65))_Python语句print(chr(ord('B')))的执行结果是
- 一枚程序猿的MacBook M1详细体验报告
- 金蝶K3 SQL报表系列-客户科目余额表(可用于生成客户保证金查询报表等)
- python棋盘放米的故事阅读答案_棋盘摆米的故事你得到了什么启发
- 【01 DualCam Framework】
- ST-PUZZLE-2.0(一个益智游戏)
- 计算机加减乘除运算原理