当前位置: 首页 > news >正文

上海网站建设 排名小说系统+wordpress

上海网站建设 排名,小说系统+wordpress,深圳建网站哪,网站建设次年续费合同windows版客户端更适合大多数人~ 文章目录 一. udp客户端windows版二.Tcp服务器的实现总结 一、udp客户端windows版 首先我们将上一篇文章中实现的udp大型聊天室的代码进行修改#xff0c;注意我们只修改服务端代码将代码修改的很简单就好#xff0c;因为我们只是做一个如何… windows版客户端更适合大多数人~ 文章目录 一. udp客户端windows版二.Tcp服务器的实现总结 一、udp客户端windows版 首先我们将上一篇文章中实现的udp大型聊天室的代码进行修改注意我们只修改服务端代码将代码修改的很简单就好因为我们只是做一个如何用windows做一个客户端的例子。 我们服务端头文件不变将.cc文件中的hander方法简化一下 static void Usage(string proc) {coutUsage:\n\tproc local_port\n\n; } void handerMessage(int sockfd,string clientip,uint16_t clientport,string message) {string response message;response [server echo]: ;struct sockaddr_in client;socklen_t len sizeof(client);bzero(client, sizeof(client));client.sin_family AF_INET;client.sin_port htons(clientport);client.sin_addr.s_addr inet_addr(clientip.c_str());// 构建好结构体后我们要把处理的数据发给谁呢当然是客户端了客户端给我们发数据我们再将处理后的数据发回给客户端sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)client, len); } // ./udpServer port int main(int argc,char* argv[]) {if (argc!2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port atoi(argv[1]);unique_ptrudpServer usvr(new udpServer(handerMessage,port));usvr-InitServer();usvr-start();return 0; } 接下来我们开始演示如何在windows环境下编写udp客户端的代码 首先我们需要包含头文件以及lib的一个库 #include iostream #include WinSock2.h #include string #pragma comment(lib,ws2_32.lib)然后我们需要启动windows的套接字并且对winsocket进行初始化 int main() {WSAData wsd;//启动Winsock//进行Winsocket的初始化windows初始化socket网络库申请2.2的版本if (WSAStartup(MAKEWORD(2, 2), wsd) ! 0){cout WSAStartup Error WSAGetLastError() endl;return 0;}else{cout WSAStartup Success endl;} } startup就是启动的接口里面的参数的意思是初始化socket网络库申请2.2的版本。如果startup这个函数的返回值等于0就说明启动成功否则就启动失败我们就打印一下。然后就和linux上的一样创建套接字即可 当然我们客户端需要知道服务端的ip和端口号并且用户一般是不知道这些东西的所以我们要做到让用户直接启动就能连接windows我们可以将服务器的ip和端口号放在一个文件中也可以直接定义 这里的ip和端口号填的是你的服务器可不要和我一样-.-。 然后我们就创建套接字 SOCKET sock socket(AF_INET, SOCK_DGRAM, 0);if (sock SOCKET_ERROR){cout socket ERROR WSAGetLastError() endl;return 1;}else{cout socket success endl;}struct sockaddr_in server;memset(server, 0, sizeof(server));server.sin_family AF_INET;server.sin_port htons(serverport);server.sin_addr.s_addr inet_addr(serverip.c_str());string line;while (true){cout Please Enter# ;getline(cin, line);int n sendto(sock, line.c_str(), line.size(), 0, (struct sockaddr*)server, sizeof(server));if (n 0){cerr sendto error endl;break;}//接收服务器的数据char buffer[1024];struct sockaddr_in client;int len sizeof(client);n recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)client, len);if (n 0){buffer[n] 0;}cout [server echo]: buffer endl;} 这里与linux中是完全一样的最后我们还需要将使用库的相关资源全部释放掉 //最后将使用库的相关资源全部释放掉 关闭套接字的文件描述符closesocket(sock);WSACleanup();return 0; } int main() {WSAData wsd;//启动Winsock//进行Winsocket的初始化windows初始化socket网络库申请2.2的版本if (WSAStartup(MAKEWORD(2, 2), wsd) ! 0){cout WSAStartup Error WSAGetLastError() endl;return 0;}else{cout WSAStartup Success endl;}SOCKET sock socket(AF_INET, SOCK_DGRAM, 0);if (sock SOCKET_ERROR){cout socket ERROR WSAGetLastError() endl;return 1;}else{cout socket success endl;}struct sockaddr_in server;memset(server, 0, sizeof(server));server.sin_family AF_INET;server.sin_port htons(serverport);server.sin_addr.s_addr inet_addr(serverip.c_str());string line;while (true){cout Please Enter# ;getline(cin, line);int n sendto(sock, line.c_str(), line.size(), 0, (struct sockaddr*)server, sizeof(server));if (n 0){cerr sendto error endl;break;}//接收服务器的数据char buffer[1024];struct sockaddr_in client;int len sizeof(client);n recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)client, len);if (n 0){buffer[n] 0;}cout [server echo]: buffer endl;}//最后将使用库的相关资源全部释放掉 关闭套接字的文件描述符closesocket(sock);WSACleanup();return 0; } 所以我们可以发现windows客户端和linux客户端的区别在于windows需要先启动winsocket并且初始化网络库最后还需要手动释放使用库的相关资源并且也要关闭套接字的文件描述符。 我们在运行的时候发现inet_addr这个函数会报错原因是vs编译器认为这个函数不安全大家可以将这个报错禁掉或者使用vs推荐的函数 注意4996代表的是我刚说的报错信息不要理解为可以禁掉任意报错要禁什么需要看你报错的编号。 二、Tcp服务器的实现 首先tcp服务器的实现一定是比udp困难的但是因为udp的特性是面向数据报所以在日常生活中使用的没有tcp广泛所以tcp我们必须要掌握和之前一样我们先创建需要用到的头文件比如tcpserver.hpp,tcpserver.cc。 接下来我们先将服务端的框架写出来 namespace server {static const uint16_t gport 8080;class TcpServer{public:TcpServer(const uint16_t port gport):_port(port),_sock(-1){}void initServer(){}void start(){}~TcpServer(){}private: int _sock; uint16_t _port;}; } 我们将udp绑定ip和端口号的时候说过实际上一款服务器的启动只需要端口号因为在绑定IP的时候我们会绑定任意ip这样只要用户知道我们的端口号他就可以访问我们的服务器所以我们的私有变量中没有ip只有port和文件描述符。在构造函数中我们直接给一个默认的端口号这样我们启动的时候可以设置自己想用的端口号也可以直接用缺省的。然后我们将server.cc文件也写一下 #include TcpServer.hpp #include memory using namespace server; static void Usage(string proc) {cout\nUasge:\n\tproc port\n\n; } //./tcpserver port int main(int argc,char* argv[]) {if (argc!2){Usage(argv[0]);exit(USE_ERR);}uint16_t port atoi(argv[1]);unique_ptrTcpServer tsvr(new TcpServer(port));tsvr-initServer();tsvr-start();return 0; } 这里还是和之前udp服务器一样唯一要说明的是我们在服务器构造的时候给了缺省其实一个参数就可以运行但是由于后面要进行演示我们还是按照./tcpserver port这样的启动方法来走。 然后我们再写一下客户端的框架 namespace client {class TcpClient{public:TcpClient(const string serverip,const uint16_t serverport):_serverip(serverip),_serverport(serverport),_sock(-1){}void initClient(){}void start(){}~TcpClient(){}private:int _sock;string _serverip;uint16_t _serverport;}; } 同样的udp客户端的一样我们就不解释了顺便也把client.cc写出来 #include TcpClient.hpp #include memory using namespace client; static void Usage(string proc) {cout\nUsage:\n\tproc serverip serverport\n\n; } // ./tcpclient serverip serverport int main(int argc,char* argv[]) {if (argc!3){Usage(argv[0]);exit(1);}uint16_t serverport atoi(argv[2]);string serverip argv[1];unique_ptrTcpClient tcet(new TcpClient(serverip,serverport));tcet-initClient();tcet-start();return 0; } 准备工作做完后我们就开始进行服务器的初始化函数的编写 我们第一步还是创建套接字不过这次我们可以加入一个日志的功能每次服务器启动可以告诉我们那些函数接口是否调用成功所以我们再创建一个log.hpp #pragma once #include iostream #include string #define DEBUG 0 #define NORMAL 1 #define WARNING 2 #define ERROR 3 #define FATAL 4 void logMessage(int level,const std::string message) {//[日志等级][时间戳/时间][pid][message]std::coutmessagestd::endl; } 我们将等级分为5个0,1,2都可以算作正常的34就说明是某部分写错或者函数运行失败然后我们就先简单的打印一下等后期Tcp服务器实现完了我们再给日志添加好玩的功能。 void initServer(){//1.创建文件套接字对象_sock socket(AF_INET,SOCK_STREAM,0);if (_sock-1){logMessage(FATAL,create socket error);exit(SOCKET_ERR);}logMessage(NORMAL,socket success);//2.进行bindstruct sockaddr_in local;bzero(local,sizeof(local));local.sin_family AF_INET;local.sin_port htons(_port);local.sin_addr.s_addr INADDR_ANY; //INADDR_ANY绑定任意地址IPif (bind(_sock,(struct sockaddr*)local,sizeof(local))0){logMessage(FATAL,bind socket error);exit(BIND_ERR);}logMessage(NORMAL,bind socket success); } tcp服务器初始化的前两步与udp是一模一样的都是先创建套接字然后再bind。首先我们创建套接字然后因为tcp是面向字节流的所以socket的第二个参数我们选择sock_stream。如果创建失败那么我们就向日志中打印信息像这种使用接口失败的那么错误等级一定是严重错误fatal,然后我们还可以写一个枚举来保存所有的退出码。 enum{SOCKET_ERR 2,USE_ERR,BIND_ERR,LISTEN_ERR}; 如果创建套接字成功我们就向日志中打印创建成功。绑定的时候我们可以看到我们将IP用INADDR_ANY绑定这个选项的意思就是绑定任意IP然后我们判断绑定是否成功如果失败就向日志中写信息并且退出。下面我们将解Tcp服务器初始化与udp不一样的点 //3.Tcp需要将套接字状态设为listen状态来一直监听因为Tcp是面向字节流的)if (listen(_sock,gbacklog)0){logMessage(FATAL,listen socket error);exit(LISTEN_ERR);}logMessage(NORMAL,listen socket success);} 首先一款Tcp服务器是面向链接的当客户端要正常的向服务器发起请求的时候客户端不能直接给服务器发送消息而是需要先建立链接这就意味着我们的服务器必须要时时刻刻准备接受客户端向我们发送的链接那么如何做到呢我们需要将socket设置为监听状态。 下面我们先看看listen这个接口的文档 第一个参数是我们使用套接字返回的文件描述符第二个参数是底层全链接长度1这里我们就不详细的解释第二个参数了后面讲tcp原理的时候再详细的讲解。要使用这个参数我们首先定义一个变量 这个变量可以是510,20之类的不能太大。如果监听成功我们就像日志写入成功的信息。 这样我们就写完了tcp服务器初始化的接口不知道大家有没有这样的疑问为什么udp不需要监听呢这是因为udp不需要链接客户端发给我们的数据就是数据本身。由于tcp是面向链接的所以tcp的第一步不是发数据而是建立链接这就是Tcp的三次握手后面讲原理的时候细谈。 下面我们编写start接口 对于一款服务器一旦启动那么必定是死循环 void start(){for (;;){}} 那么启动后我们该干什么呢在udp那里我们是接收客户端发来的消息然后再将消息处理后发回给客户端而对于tcp服务器我们刚刚也说了需要先建立链接建立链接就需要用到accept接口 注意之前udp服务器中接收消息的recvfrom在tcp是用不了的。 第一个参数是一个文件描述符后面两个参数是输出型参数调用接口会接口会自动帮我们填充结构体填充的结构体的信息是客户端的ip和端口等。accept的返回值是一个文件描述符下面我们解释一下 首先accept的后两个参数和recvfrom的后两个参数的含义是一模一样的都是帮我们填充客户端的ip和端口号最重要的是第一个参数这个参数的含义是不一样的因为accept的返回值是一个文件描述符这个文件描述符和我们之前创建套接字返回的那个文件描述符是什么关系呢我们在用listen接口的时候说过将套接字设置为监听状态就可以一直监听客户端是否要给我们发现请求链接而accept的第一个参数实际上就是监听的那个套接字因为只有成功监听到客户端的请求链接我们才可以和客户端通信所以accept返回的那个套接字才是我们真正用来和客户端通信的套接字所以我们应该将刚开始创建的私有成员变量sock改名为listensock,因为这个变量只是起到监听新链接的作用。 改名后我们就可以更容易理解这两个套接字的关系了。 void start(){for (;;){//4.server获取新链接 未来真正使用的是accept返回的文件描述符struct sockaddr_in peer;socklen_t len sizeof(peer);// sock是和client通信的fdint sock accept(_listensock,(struct sockaddr*)peer,len);//accept失败也无所谓继续让accept去获取新链接if (sock0){logMessage(ERROR,accept error,next);continue;}logMessage(NORMAL,accept a new link success);coutsock: sockendl;//5.用sock和客户端通信,面向字节流的后续全部都是文件操作serviceIO(sock);//对于一个已经使用完毕的sock我们要关闭这个sock,要不然会导致文件描述符泄漏close(sock);}} 要使用accept需要先创建结构体然后拿到返回的套接字后我们可以打印一下这个套接字。注意即使我们accept失败也无所谓因为listensock会持续监听客户端的新链接所以我们accept失败不能退出。当我们成功拿到和客户端通信需要的sock后我们就要考虑和客户端通信了这里我们专门写一个服务器与客户端通信的函数将sock传入 void serviceID(int sock){ while (true){}} 首先我们要能读到客户端发来的消息所以我们直接用以前学文件用到的read接口 这个接口很简单第一个参数是我们从哪个文件描述符里读第二个参数是要读到哪个缓冲区第三个参数是缓冲区的大小。 void serviceID(int sock){char buffer[1024];while (true){ssize_t n read(sock,buffer,sizeof(buffer)-1);if (n0){//目前我们先把读到的数据当成字符串buffer[n] 0;coutrecv message: bufferendl;} }} 我们定义一个缓冲区然后如果读取成功就在前面加上接收消息然后把消息打印出来接下里我们再简单的处理一下数据把数据转回的客户端注意我们的只是方便演示用的字符串实际上这里的数据可以是任意的比如结构化的。 write接口我们也用过第一个参数要向哪个文件描述符写入第二个参数是写入的消息的缓冲区第三个参数是缓冲区的大小。  void serviceIO(int sock){char buffer[1024];while (true){ssize_t n read(sock,buffer,sizeof(buffer)-1);if (n0){//目前我们先把读到的数据当成字符串buffer[n] 0;coutrecv message: bufferendl;//将消息转回客户端string outbuffer buffer;outbuffer[serverecho];write(sock,outbuffer.c_str(),outbuffer.size()); //多路转接解释write返回值}else if(n0){//n0说明客户端退出了logMessage(NORMAL,client quit,server me to!);break;}}} read的返回值是读到的数据的大小如果读到0说明读到了文件结尾既然读到了文件结尾那么客户端肯定是退出了。这就类似于管道当写端不写了并且把文件描述符关闭了我们的读端就会把数据读完后然后读到文件结尾返回0所以读到0就代表客户端退出了。这也就是为什么我们在start中一旦serviceIO后就直接关闭了文件描述符因为serviceIO是一个死循环一旦循环退出就说明客户端退出了既然客户端退出了那么我们的服务端当然要将与客户端通信的文件描述符关闭。注意对于已经使用完的文件套接字我们必须关闭如果不关闭则会造成文件描述符泄漏 下面我们编写客户端的代码 客户端初始化同样也需要创建套接字我们在udp的时候就说过客户端一定要bind但是不需要程序员明确的bind,在tcp中也一样。那么tcp客户端需要listen吗当然不需要了客户端又不是服务器没人会链接客户端的所以不需要监听那么需要accept吗答案是也不需要因为客户端没有人去链接所以不需要。 void initClient(){// 1.创建套接字_sock socket(AF_INET,SOCK_STREAM,0);if (_sock0){coutsocket errorendl;exit(2);}// 2.客户端要bind吗必须要 要程序员显式的bind吗不需要// 3.客户端要listen吗不需要没人去连客户端所以不需要// 4.客户端要accept吗不需要// 5.客户端要发起链接。} 没错我们客户端初始化的代码非常的简洁就只需要创建套接字即可。 那么客户端启动需要干什么呢实际上就是我们的第5点我们要发起链接。 下面我们认识一下connect接口 第一个参数是文件描述符第二个参数和第三个参数是我们要传结构体这个结构体是我们要和哪个服务器建立链接里面就是哪个服务器的ip和port。仔细看我们红色圈出来的部分就会发现我们刚刚初始化的时候说客户端不用显式的bind可以看到在connect接口中会自动帮我们绑定如果绑定成功会返回0. void start(){struct sockaddr_in server;bzero(server,sizeof(server));server.sin_family AF_INET;server.sin_port htons(_serverport);server.sin_addr.s_addr inet_addr(_serverip.c_str());//connet的时候操作系统会帮客户端bind 返回值等于0成功if (connect(_sock,(struct sockaddr*)server,sizeof(server))!0){cerrsocket connect errorendl;}else {//链接成功客户端要干什么与服务端通信}} 我们首先填充结构体将服务端的ip和port填充完毕后我们就可以进行连接如果连接失败我们就打印错误只有成功我们才开始与服务端通信那么如何通信呢实际上与服务端accept后一样因为tcp是面向字节流的所以我们通信的过程都是文件操作。 else {//链接成功客户端要干什么与服务端通信string message;while (true){coutEnter# ;getline(cin,message);//将消息发送给服务端write(_sock,message.c_str(),message.size());//读取服务端给我们发送的消息char buffer[1024];int n read(_sock,buffer,sizeof(buffer)-1);if (n0){buffer[n] 0;coutServer回显# bufferendl;}else {break;}}} 这里就是死循环式的给服务器发消息我们直接用getline将cin中输入的消息保存到string中然后将这个消息写入文件描述符接下来我们还需要读取服务端给我们发送的消息因为read接口需要缓冲区所以我们定一个缓冲区如果read的返回值大于0说明消息读到缓冲区中我们就在读取到字节数的位置放一个\0然后打印这个消息如果返回值等于0说明写端不写入了并且关闭了文件描述符所以我们就直接退出循环并且关闭文件描述符我们这里就直接用析构函数关闭即可。 ~TcpClient(){if (_sock!-1){close(_sock);}} 下面我们就运行起来演示一下 运行后我们可以用netstat命令查看服务器信息n代表将端口号等信息用数字显示l代表监听tp代表tcp,下面我们开启客户端 大家可以猜一下为什么我们创建的套接字是4号呢首先我们都知道OS会默认打开3个文件描述符分别是0,1,2,那么我们为什么不是创建的3呢不是说文件描述符对应数组的下标吗这是因为我们服务器中创建listensock套接字用了3号所以我们调用accept创建的套接字是4号套接字。 当我们用客户端连接上服务端后查询所有的tcp发现有两个服务端 这是因为我们当前是在本地通信的所以有两个链接客户端到服务端服务端到客户端。正常情况下都是不同的电脑进行连接这种情况下查看就只有一条链接了。 当然我们在写代码的时候其实故意留了一个问题如果有多个客户端发消息是这样的 为什么只有先链接的那个客户端可以发消息呢 当我们将先链接的那个客户端退出后为什么消息一股脑全发来了这是因为我们当时写代码的时候只针对一个客户端谁进来谁就死循环式的收发消息 只有当一个客户端退出了另一个客户端才会收到消息在下一篇文章中我们将用多进程多线程线程池版本的serviceIO届时这种问题就不会存在了。 总结 tcp服务器的实现相较于udp服务器并没有多多少东西所以只有udp明白了那么简单的tcp服务器还是很好实现的下一篇才是我们tcp服务器的重点。
http://www.huolong8.cn/news/95046/

相关文章:

  • 自考网站建设与管理资料成都网页设计师
  • c2c网站制作定制网站开发食道里感觉有东西堵
  • 宁波网站怎么建设网站建设 深圳
  • 做证券考试的网站wordpress主题js文件在哪
  • 工商注册在哪个网站前端开发是程序员吗
  • 薛城网站建设怎么弄一个自己的网址
  • 做网站虚拟主机推荐为什么想做网站运营
  • 赵公口网站建设网络推广app是干什么的
  • 卖高权重网站做跳转网站主办者和所有者区别
  • 网站简介 更改做网站和推广
  • 深圳比较好的ui设计公司小果seo实战培训课程
  • 网站制作定制图pc网站如何做sp
  • 最新网站建设软件wordpress 虾米音乐插件
  • 建站价格会差网站空间多大
  • 学校网站资源建设方案制作排行榜的软件
  • 深圳网站专业建设公司政协门户网站建设方案
  • 本科学计算机是做网站吗网站开发费用包括美工费吗
  • 网络推广营销网站建设专家flash做网站的论文
  • 网站开发技术代码源码可以做网站吗
  • 阜阳市住房和城乡建设局网站网络营销是什么样子的
  • 产品网站免费模板下载地址做一个宣传网站的策划书
  • 360网站页面的工具栏怎么做网站移动端的设计思想
  • hype做网站动效wordpress kallyas
  • 做海淘是在哪个网站好文学写作网站
  • 开封网站推广公司业务型网站做seo
  • 在局网站 作风建设方案开发app需要的技术
  • 成都市建设相关网站做外汇看新闻在什么网站看
  • 自己做网站不推广网站开始怎么做
  • 品牌手表网站移动端网站咋做
  • 网站优化招商有哪些做平面设计好的网站有哪些