73)搭建服务器
其实搭建服务器步骤都是固定的,
那么我们接下来 我们建立一个解决方案,然后在我们的解决方案里面放我们的多个工程:
注意:
1-->我们绑定的端口号一般都是大于1024的 因为0~1023是电脑中软件的端口 ,一旦我们绑定我们建立的服务器的端口号和我们的应用程序冲突,绑定就会失败
我们可以尝试一下 就是绑定bind函数那块 我们运行两次-->就能看到绑定失败的效果
2--->还有我们在调试的时候,最后会卡在recvfrom函数那块 ,因为只要服务器不收到消息,就会一直卡在recvfrom函数,直到收到来自客户端的消息
为什么会这样:因为recvfrom(sock,~~~~~)函数里面的sock默认的属性是 阻塞 :就是一直等客户端的消息,直到来了消息,才往下执行,否则就卡在这里
还有 非阻塞属性:就是立即返回(不管recvfrom收到消息还是没收到)
socket默认属性是 阻塞
改变socket的这个属性:
3-->什么时候用阻塞模式,什么时候用非阻塞模式?
然后要是阻塞模式:假如我发送的是8k 要是我的发送缓冲区只剩下1k了,那么sentto函数就等着,直到发送缓冲区有了8k再发送,然后返回
非阻塞模式: 假如我发送的是8k 要是我的发送缓冲区只剩下1k了,那么sentto函数也发送,然后返回,但是会返回告诉你发送成功了 还是失败了。
4-->其实在应用层和传输层之间有一个软件抽象层--->socket层
5-->看发送缓冲区大小和接收缓冲区大小:
getsockopt函数的最后一个参数写错了 他要的是长度,所以 我们直接给nRecvLen和nSendLen赋值是4,因为nRecvSize和nSentSize是int类型
结果nRecvSize和nSentSize的返回值都是65536 也就是64k,(我的电脑是win10系统) 要是win7系统,就是8k
5-->子网划分:
搭建服务器一般步骤:
首先 我们建立一个解决方案:
然后在解决方案里面添加工程:
然后添加我们主文件代码(基本步骤)
然后我们添加基本的代码,我们先来处理第一步:
继续添加我们的代码:
现在的第一步的完整代码样子:
开始我们的第二步:创建套接字和绑定(就是固定这个服务器的IP地址和端口号)
看我们的网络属性:
------>看我们的网络属性:
第一步:
第二步:
第三步:
第四步:
第五步:
接下来添加函数的变量:
那个bind函数的变量说明:
要是参数怎么填 我们可以看下面的例子:
之间遇到这个问题:
第二步完成:
接下来就是第三步,先看看recvfrom函数的帮助文档:
倒数第二个:指向装有源地址的缓冲区。
倒数第一个:_Inout_opt_ int *fromlen 很明显_Inout_opt_是可选的,参数:指针,指向倒数第二个缓冲区长度值
然后第三步和第四步:
最终的完整代码:
1 #include<iostream> 2 #include<Winsock2.h> 3 using namespace std; 4 5 #pragma comment(lib, "ws2_32.lib") 6 7 int main() 8 { 9 //我们假定搭建服务器的过程看成是我们卖小吃 10 11 //第一步就是选一个小吃的种类 --->对应就是 载入库 12 WORD wVersionRequested; 13 WSADATA wsaData; 14 int err; 15 wVersionRequested = MAKEWORD(2, 2);//网络的版本号,2.2版本 16 err = WSAStartup(wVersionRequested, &wsaData); 17 if (err != 0) { 18 printf("WSAStartup failed with error: %d\n", err); 19 return 1; 20 } 21 if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { 22 printf("Could not find a usable version of Winsock.dll\n"); 23 WSACleanup(); 24 return 1; 25 } 26 else 27 printf("The Winsock 2.2 dll was found okay\n"); 28 29 30 31 //第二步 找个人卖小吃 同时定好在哪里卖小吃 --->创建socket 绑定bind 32 SOCKET sock= socket(AF_INET,SOCK_DGRAM ,IPPROTO_UDP ); 33 if(sock==INVALID_SOCKET )//socket创建失败 34 { 35 WSACleanup();//既然套接字创建失败,就卸载库 36 return 1; 37 } 38 sockaddr_in addr; 39 addr.sin_family=AF_INET;//协议簇,和刚刚创建socket的那个第一个参数一样 40 addr.sin_port=htons(1234);//端口号 41 addr.sin_addr.s_addr = inet_addr("192.168.0.32");//IP地址 42 if(bind(sock,(const struct sockaddr *)&addr,sizeof(addr))==SOCKET_ERROR)//没有绑定成功 43 { 44 closesocket(sock); 45 WSACleanup();//卸载库 46 return 1; 47 } 48 49 //第三步,收顾客买东西的钱 --->接收来自别人消息recvfrom() 50 char recBufferSize[1024]={0};//存储来自别人传来的话(这个是接收缓冲区,1024是你设定的大小) 51 sockaddr_in recMessage;//存储另一方的IP和端口号信息 52 int nsize=sizeof(recMessage); 53 int resnum=recvfrom(sock,recBufferSize,sizeof(recBufferSize),0,(sockaddr *)&recMessage,&nsize); 54 if(resnum>0) 55 { 56 cout<<"对方发来的消息是:"<<recBufferSize<<" "<<"对方的IP是:"<<endl; 57 //发送信息 58 cin>>recBufferSize; 59 sendto(sock,recBufferSize,sizeof(recBufferSize),0,(SOCKADDR *) & recMessage, sizeof (recMessage)); 60 } 61 //第四步 收摊 ---->就是卸载库 62 63 system("pause"); 64 return 0; 65 }
提示:
1-->我们可以调试,看他的运行步骤:
随便下断点
2-->学会看帮助文档,然后看不懂的 再百度 搜搜函数