网络编程基础第四讲阻塞模型

一丶阻塞模型简介

  不知道大家有没有注意到.我们客户端 或者服务端.的TCP 收发数据的时候(send/recv)如果接受不到数据就一直不返回.从而造成我们网络的阻塞.程序无法正常执行.

不过针对这一方法.我们可以开一个线程去专门接受数据.或者发送数据.

这个就是我们常说的阻塞.

只要我们创建的套接字都是阻塞模型. 就是说数据接受不到不返回.

我们可以设置为非阻塞.就是不管数据有没有来到都会返回.如果来到.会有通知.我们可以编程接受数据.

设置非阻塞模式方法

  ioctlsocket(SOCKET s, long cmd, u_long *arpg);

改变套接字模式.为飞租she.

 

二丶阻塞模式迭代模式 与 并发连接模式

  1.阻塞模式的迭代模式 就是指每次只服务一个连接.只有服务完当前的客户端连接之后.才会继续服务下一个客户连接

  2.并发连接模式 通过多线程.可以同时服务多个链接.没一个线程处理一个客户端的连接.

阻塞迭代模式步骤

  1.生成一个函数.绑定本地地址跟监听.

  2.生成一个函数.专门接受一个客户端连接.并且返回对应连接的套接字.

  3.处理没一个客户端的连接.实现接受跟发送数据.

  4.关闭一个连接.

其实就是讲创建服务端网络做了一个封装.

如下代码. 一个.h文件.存放函数声明.一个.cpp封装了网络连接的代码.

.h文件:

#pragma once#include "stdafx.h"#include <WinSock2.h>#include <iostream>#pragma comment(lib,"ws2_32.lib")using namespace std;#include "initSocket.h"void DebugLog(TCHAR *str);//初始化数据int initSocket();//1.创建套接字.绑定地址,开始监听SOCKET BindAnListen(int nBacklog);//接受连接分装SOCKET AccepeConnect(SOCKET hSocket);//接受跟发送数据BOOL ClientReadAnWriteData(SOCKET hSocket);//关闭数据连接BOOL ColseConnect(SOCKET hSocket);

.cpp实现.

#include "initSocket.h"void DebugLog(TCHAR *str){    cout << str << WSAGetLastError() << endl;}//初始化数据int initSocket(){    WSADATA data;if (WSAStartup(MAKEWORD(2, 2), &data))    {        DebugLog(TEXT("initsocket faile"));return 0;    }}//1.创建套接字.绑定地址,开始监听SOCKET BindAnListen(int nBacklog){//创建套接字BOOL bRet = FALSE;    SOCKET hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (INVALID_SOCKET == hSocket)    {        DebugLog(TEXT("BindAnListen Fail"));return INVALID_SOCKET;    }                //绑定套接字    sockaddr_in addr;    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//htonl addr_anyaddr.sin_family = AF_INET;    addr.sin_port = htons(8524);    bRet =  bind(hSocket, (sockaddr *)&addr, sizeof(addr));if (SOCKET_ERROR == bRet)    {        DebugLog(TEXT("bind fail"));        closesocket(hSocket);        WSACleanup();return INVALID_SOCKET;    }//监听套接字bRet = FALSE;    bRet =  listen(hSocket, nBacklog);if (SOCKET_ERROR ==bRet)    {        DebugLog(TEXT("Listen fail"));        closesocket(hSocket);        WSACleanup();return INVALID_SOCKET;    }return hSocket;}//接受连接分装SOCKET AccepeConnect(SOCKET hSocket){    sockaddr_in addr;int nSize = sizeof(addr);    SOCKET hNewSocket = accept(hSocket, (LPSOCKADDR)&addr, &nSize);if (hNewSocket == INVALID_SOCKET)    {        DebugLog(TEXT("Accept An Connect Fail"));return INVALID_SOCKET;    }return hNewSocket;}//接受跟发送数据BOOL ClientReadAnWriteData(SOCKET hSocket){char szBuffer[1024] = { NULL };int nBufferSzie = sizeof(szBuffer);//循环处理数据int nRecvBytes = 0;do{        nRecvBytes = recv(hSocket,szBuffer, nBufferSzie, 0);if (SOCKET_ERROR == nRecvBytes)        {            DebugLog(TEXT("Recv Data Fail"));return FALSE;        }else if (0 != nRecvBytes)        {
       szBuffer[nRecvBytes] = 0;                 cout
<< "接受到的数据为: " << szBuffer << endl;//接着循环发送回去.int nSendDataBytes = 0;while (nSendDataBytes < nRecvBytes)            {int nRetValue = send(hSocket, szBuffer, nBufferSzie, 0);if (nRetValue > 0)                {                    nSendDataBytes = nSendDataBytes + nRetValue;//每次发送的数据都增加.这样就会发送过去了}else if (nRetValue == SOCKET_ERROR)                {                    DebugLog(TEXT("发送数据失败"));return FALSE;                }else{//send 返回0 也就是send失败了.客户端关闭了DebugLog(TEXT("发送数据失败,客户端已经关闭了"));return FALSE;                }            }        }    } while (0 != nRecvBytes);return FALSE;}BOOL ColseConnect(SOCKET hSocket){//shutdown 跟 closesocket一样.不过 TCP 会发送一个FIN分段.给对方表名已经完成数据发送if (shutdown(hSocket,SD_SEND) == SOCKET_ERROR)    {        DebugLog(TEXT("关闭连接失败"));return FALSE;    }//注意.客户端会发送一个数据.不写也可以.return TRUE;}

上面的代码只是把我们网络创建的一些步骤给封装了.并没有实际编写我们用的代码.

在main函数中使用.只服务一个socket操作

// Server.cpp : 定义控制台应用程序的入口点。//#include "initSocket.h"int main(){//初始化    initSocket();//1.绑定并且监听SOCKET hSocket = BindAnListen(1);if (INVALID_SOCKET == hSocket)    {        DebugLog(TEXT("main Bind Fail"));goto Opt;    }// 2.循环接受套接字连接while (true)                            //主要代码是这里.    {//接受客户端连接SOCKET hRetSocket = AccepeConnect(hSocket);if (INVALID_SOCKET == hRetSocket)        {            DebugLog(TEXT("main accept Fail"));break;        }        //读取数据.if (FALSE == ClientReadAnWriteData(hRetSocket))        {//只服务一个socket.对其进行读取写入操作.然后下方进行关闭.break;        }if (ColseConnect(hRetSocket))        {break;        }    }Opt:    getchar(); //等待一下.观看错误内容    ColseConnect(hSocket);return 0;}

 

主要就是服务端的代码.客户端进行发送数据即可.

 

 


©著作权归作者所有:来自51CTO博客作者独孤一笑的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 基于OAC的员工离职数据分析
  2. Jira/Confluence的备份、恢复和迁移
  3. 【DB笔试面试352】在Oracle数据库中,哪些操作会导致索引失效?--UNU
  4. Exadata X8 系列硬件的新变化
  5. 当餐饮行业创新与变革遇到完全自治的云计算的时候
  6. 【DB笔试面试164】在Oracle中,如何彻底停止expdp数据泵进程?
  7. ORA-01578和ORA-26040--NOLOGGING操作引起的坏块-错误解释和解决
  8. 如何让excel单元格内只能输入指定内容?
  9. 从运维角度看中大型网站架构的演变之路

随机推荐

  1. android 自定义图片剪裁
  2. TextView跑马灯
  3. (Android) Download Images by AsyncTask
  4. android customactivityoncrashchau 程序
  5. android   CheckBox 用法
  6. android照相及照片上传
  7. Android第五期 - 更新自己的apk本地与网
  8. 使用程序创建Android桌面快捷方式
  9. android下拉菜单spinner的使用方法
  10. Android Studio compile error : enum co