推广网站报价,优秀网站网址,用php做购物网站,网站建设专业团队图片最简单的一对一的服务端网络端通信(socket) Socket#xff08;IP地址#xff1a;端口号#xff09;#xff0c;例如#xff1a;如果IP地址是210.37.145.1#xff0c;而端口号是23#xff0c;那么得到套接字就是(210.37.145.1:23) socket可以理解成计算机提供给程序员的接…最简单的一对一的服务端网络端通信(socket) SocketIP地址端口号例如如果IP地址是210.37.145.1而端口号是23那么得到套接字就是(210.37.145.1:23) socket可以理解成计算机提供给程序员的接口数据在客户端和服务端之间的socket之间传输。socket把复杂的TCP/IP协议封装对于程序员来说只要利用好函数就可以实现数据通信。 TCP提供了stream和datagram两种通信机制所以socket分这两种。 stream的类型是SOCK_STREAM,采用TCP协议TCP协议在计算机网络中是安全可靠的有连接的协议。datagram的类型是SOCK_DGRAM,采用的是UDP协议UDP是不可靠的协议现在在实际应用开发中主要采用的是TCP。 服务端主要流程创建socket—bind绑定ip和port—listen监听客户端连接请求—accept接受连接----数据传输----close关闭连接 int listenfd;listenfdsocket(AF_INET,SOCK_STREAM,0);//在socket编程中AF_INET是必须的等同于固定搭配//socket创建成功后如果返回值是-1的话说明创建失败为0的时候就是创建成功if(listenfd-1){printf(socket create fail\n);return -1;}struct sockaddr_in serveraddr;//定义一个用来处理网络通信的数据结构sockaddr_in分别将端口和地址存储在两个结构体中//sin_family协议族memset(serveraddr,0,sizeof(serveraddr));serveraddr.sin_familyAF_INET;serveraddr.sin_addr.s_addr htonl(INADDR_ANY);//serveraddr.sin_addr.s_addratoi(argv[1]);// specify ip addressserveraddr.sin_porthtons(atoi(argv[1]));//specify port//printf(%s %s\n,argv[1],argv[2]);if(bind(listenfd,(struct sockaddr *)serveraddr,sizeof(serveraddr))!0){printf(bind failed \n);return -1;}INADDR_ANY 表示监听0.0.0.0地址socket只绑定端口不绑定本主机的某个特定ip让路由表决定传到哪个ip0.0.0.0地址表示所有地址、不确定地址、任意地址一台主机中如果有多个网卡就有多个ip地址 htons()把short型值转成按网络字节顺序排列的short型值 htonl()把long型值转成按网络字节顺序排列的long型值 假设你已经有了一个sockaddr_in结构体ina你有一个IP地址132.241.5.10 要储存在其中你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。使用方法如下
ina.sin_addr.s_addr inet_addr(“132.241.5.10”); if(listen(listenfd,5)!0){printf(Listen failed\n);close(listenfd);return -1;}backlog 5 是未经过处理的连接请求队列可以容纳的最大数目。 int clintfd;//socket for clientint socklensizeof(struct sockaddr_in);struct sockaddr_in client_addr;clintfdaccept(listenfd,(struct sockaddr*)client_addr,(socklen_t *)socklen);if(clintfd-1)printf(connect failed\n);elseprintf(client %s has connnected\n,inet_ntoa(client_addr.sin_addr));inet_ntoa将网络地址转换成“.”点隔的字符串格式。char buffer[1024];while (1){int iret;memset(buffer,0,sizeof(buffer));iretrecv(clintfd,buffer,sizeof(buffer),0);if (iret0) {printf(iret%d\n,iret); break; }printf(receive :%s\n,buffer);strcpy(buffer,ok);//reply cilent with okif ( (iretsend(clintfd,buffer,strlen(buffer),0))0) { perror(send); break; }printf(send :%s\n,buffer);}// 6th close socketclose(listenfd); close(clintfd);对于服务端来说有两个socket这里该如何理解呢 一开始socket函数, 不管在客户端还是在服务端, 创建的都是主动socket, 但是在服务端经过listen(), 后把其转变为listen_socket_fd(被动监听socket),经过accept()后转变为connect_socket_fd(已连接socket). 在转变为connect_socket_fd之前, 都是同一个socket, 只不过是socket的状态改变了, 但是服务端经过accept()后返回的socket是新的socket, 用于连接后的read()/write() 假设只用一个socket完成整个过程. 那么这个socket就会一直被占用, 而不能被另外的客户端请求, 造成了服务端的性能极其低下, 如果没有存储后面的客户端请求, 就会被错过而丢弃, 因为当前的socket正在与当前一个客户端的socket建立连接.
客户端 socket-connect struct sockaddr_in servaddr;memset(servaddr,0,sizeof(servaddr));servaddr.sin_family AF_INET;servaddr.sin_port htons(atoi(argv[2])); // servers portservaddr.sin_addr.s_addrinet_addr(argv[1]);//servers ipif (connect(sockfd, (struct sockaddr *)servaddr,sizeof(servaddr)) ! 0) // send request to server for connection{ perror(connect); close(sockfd); return -1; }多进程的一个服务端服务多个客户端 具体实现就是在accept部分增加一个外层的循环 子进程执行完之后就return 0或者exit(0)直接退出去。 还有一个问题就是查看打开的进程编号可以发现父进程和子进程文件描述符一样的。对于父进程来说只需要监听连接不需要连接后的fd对子进程来说listenfd也是不需要的。但是fork会生成一份副本导致父子进程都有listenfd和connectfd所以可以在父进程中关掉connectfd子进程中关掉listenfd。为什么要这么做因为fd是一种资源维护一个fd不难但是很多客户端就会有很多冗余的fd,造成资源浪费。而且一个进程能打开的fd是有限的。
多进程服务程序的退出 子进程收到退出信号ctrlc在子进程设置signal(2,childexit)signal(15,childexit)。然后子进程关闭客户端的fd再退出。 父进程会关闭listenfd然后通知所有子进程退出然后退出。
TCP长连接和心跳机制的实现 短连接 短连接是指通信双方有数据交互时就建立一个TCP连接数据发送完成后则断开此TCP连接管理起来比较简单存在的连接都是有用的连接不需要额外的控制手段 连接→数据传输→关闭连接 所谓长连接指在一个TCP连接上可以连续发送多个数据包在TCP连接保持期间如果没有数据包发送需要双方发检测包以维持此连接一般需要自己做在线维持不发生RST包和四次挥手。 连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接一个TCP连接通道多个读写通信 长连接多用于操作频繁读写点对点的通讯而且连接数不能太多情况。每个TCP连接都需要三步握手这需要时间如果每个操作都是先连接再操作的话那么处理速度会降低很多所以每个操作完后都不断开次处理时直接发送数据包就OK了不用建立TCP连接。例如数据库的连接用长连接 如果用短连接频繁的通信会造成socket错误而且频繁的socket 创建也是对资源的浪费。 而像WEB网站的http服务一般都用短链接http1.0只支持短连接1.1keep alive 带时间操作次数限制的长连接因为长连接对于服务端来说会耗费一定的资源而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源如果用长连接而且同时有成千上万的用户如果每个用户都占用一个连接的话那可想而知吧。所以并发量大但每个用户无需频繁操作情况下需用短连好
具体实现 服务端和客户端约定超时时间假设35秒 如果服务端35秒没收到报文认为客户端异常主动关闭 客户端35秒内没有任何业务发送心跳报文以维持连接。
客户端在空闲时发送心跳报文服务端的读函数增加一个超时参数超时就断开连接不超时就回复成功。
实现文件的上传和下载功能、异步通信机制实现快速传输。
主要包含文件传输的服务端模块支持上传下载 文件上传的客户端文件下载的客户端。 客户端分成两个是因为让程序结构更简单模块化服务端不分开因为它是网络服务程序分成两个的话就要两个监听的端口配置网络参数更麻烦比如路由器防火墙。
文件上传客户端登录意义在于协商与服务端协商文件传输参数最重要参数就是文件存放目录客户端的A目录存在服务端的B目录 客户端获取本地目录的文件清单假设有100个文件一个循环每次先传文件信息名字大小时间,再传内容。 结束后客户端休息几秒再重新获取本地目录的文件清单。
注意用于系统内部文件传输所以客户端程序常驻内存每隔几秒就传输一次。客户端上传成功后直接删除本地文件就可以。
定义一个结构体存储心跳目录等信息。
服务端只要之前的参数就可以客户端通过登录报文将更多的参数传到服务端。 服务端再修改相应的代码。处理登录报文如果是1就完成上传功能主函数。 首先服务端调用_xmltoarg方法解析登录报文如果是1或者2发送ok给客户端否则发送failed给客户端。如果登陆失败美没收到服务端回应直接退出。 如果类型为1调用RecvFilesMain()
void RecvFilesMain()
{while(true){ memset(recvbuf,0,sizeof(recvbuf));memset(sendbuf,0,sizeof(sendbuf));如果接收客户端的报文read失败超时记录日志,return如果接收缓存内容是心跳报文给客户端回复ok处理上传文件的请求报文}}客户端文件信息的上传怎么实现 服务端怎么处理这些信息 传输文件的内容 sendfile函数实现。参数有连接的socketfd文件名文件大小。 异步通讯三种实现方法 1、多进程服务端客户端后fork一个子进程子进程负责接收信息父进程发送信息 2、多线程。 3、I/O复用技术
同步的话客户端发送报文要等到接受ok再发送第二个10000个数据需要6秒。异步的话父进程发送报文子进程接受ok的成功信息1秒。
如果是10万的话同步每秒2000左右异步每秒8万左右。
I/O复用就是没有数据的话不等待直接返回。每秒差不多6万低一点原因就是有数据的话会等待数据搞完再发送当然低一点。