关于socket的认识理解

来源:互联网 发布:域名交易新闻 编辑:程序博客网 时间:2024/05/01 09:08

转:http://kb.cnblogs.com/page/188594/

对TCP/IP、UDP、Socket编程这些词你不会很陌生吧?随着网络技术的发展,这些词充斥着我们的耳朵。那么我想问:

  1. 什么是TCP/IP、UDP?

  2. Socket在哪里呢?

  3. Socket是什么呢?

  4. 你会使用它们吗?

  什么是TCP/IP、UDP?

  TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

  UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

  这里有一张图,表明了这些协议的关系。    

图1

ARP (地址解析协议)是一个位于TCP/IP协议栈中的底层协议,用于映射计算机的物理地址与网络IP地址。根据主机发送的IP地址获取主机的MAC地址。

RARP的与ARP正好相反

Ping(因特网包探索器)是一个用于测试网络连接量的程序,它使用ICMP(因特网网控制报文协议)。Ping发送一个ICMP请求信息给目的地并报告是否收到所希望的ICMP应答。来检查网络是否通畅或者网络连接速度的ICMP应答。


ICMP与IGMP的区别

ICMP协议是指英文全称(Internet Control Message Protocol),就是网际控制信息协议。主要是用于补充IP传输数据报的过程中,发送主机无法确定数据报是否到达目标主机。ICMP报文分为出错报告报文和查询报文两种。若数据报不能到达目标主机,ICMP出错报告报文可以以回送信息的方式,向源主机发去信息,并不能纠正数据报中的任何出错。除了出错报告,ICMP还可以诊断出某些网络问题,这就是ICMP的查询报文。而IGMP协议是指英文全称(Internet Group Management Protocol),网络组管理协议。主要用于建立和管理多播组,对IP分组广播进行控制。其次两者的区别:internet控制消息协议ICMP是用于报告错误并代表IP对消息进行控制。IP运用互联组管理协议IGMP来告诉路由器,某一网络上指导组中的可用主机。ICMP源抑制消息:当TCP/IP主机发送数据到另一主机时,如果速度达到路由器或者链路的饱和状态,路由器发出一个ICMP源抑制消息。

  

TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IP与UDP的关系了吧。

  Socket在哪里呢?

  在图1中,我们没有看到Socket的影子,那么它到底在哪里呢?还是用图来说话,一目了然。

图2

  原来Socket在这里。

  Socket是什么呢?

  Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面(Facade)模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

  你会使用它们吗?

  前人已经给我们做了好多的事了,网络间的通信也就简单了许多,但毕竟还是有挺多工作要做的。以前听到Socket编程,觉得它是比较高深的编程知识,但是只要弄清Socket编程的工作原理,神秘的面纱也就揭开了。

  一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。    生活中的场景就解释了这工作原理,也许TCP/IP协议族就是诞生于生活中,这也不一定。

  

图3

  先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

服务端的socket与固定的端口相连,而客户端的socket所连接的端口不固定。

  在这里我就举个简单的例子,我们走的是TCP协议这条路(见图2)。例子用MFC编写,运行的界面如下:


图4


图5

  在客户端输入服务器端的IP地址和发送的数据,然后按发送按钮,服务器端接收到数据,然后回应客户端。客户端读取回应的数据,显示在界面上。

  下面是接收数据和发送数据的函数:

int Receive(SOCKET fd, char *szText, int len){    int cnt;    int rc;    cnt = len;    while(cnt>0)    {        rc= recv(fd, szText, cnt, 0);        if(rc == SOCKET_ERROR)        {            return -1;        }        if(rc == 0)        {            return len-cnt;        }        szText += rc;        cnt -= rc;    }    return len;}int Send(SOCKET fd, char *szText, int len){    int cnt;    int rc;    cnt = len;    while(cnt > 0)    {        rc = send(fd, szText, cnt, 0);        if(rc == SOCKET_ERROR)        {            return -1;        }        if(rc == 0)        {            return len-cnt;        }        szText += rc;        cnt -= rc;    }    return len;}

  服务器端:

  在服务器端,主要是启动Socket和监听线程。

#define DEFAULT_PORT 2000void CServerDlg::OnStart(){    sockaddr_in local;    DWORDdwThreadID = 0;    local.sin_family = AF_INET;    //设置的端口为DEFAULT_PORT。    local.sin_port = htons(DEFAULT_PORT);    //IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。    local.sin_addr.S_un.S_addr = INADDR_ANY;    //初始化Socket    m_Listening = socket(AF_INET,SOCK_STREAM,0);    if(m_Listening == INVALID_SOCKET)    {        return ;    }    //将本地地址绑定到所创建的套接字上    if(bind(m_Listening, (LPSOCKADDR) & local, sizeof(local)) == SOCKET_ERROR )    {        closesocket(m_Listening);        return ;    }    //创建监听线程,这样也能响应界面上操作。    m_hListenThread = ::CreateThread(NULL, 0, ListenThread, this, 0, &dwThreadID);    m_StartBtn.EnableWindow(FALSE);    m_StopBtn.EnableWindow(TRUE);}//监听线程函数:DWORD WINAPI CServerDlg::ListenThread(LPVOID lpparam){    CServerDlg* pDlg = (CServerDlg*)lpparam;    if(pDlg == NULL) return 0;    SOCKET  Listening = pDlg->m_Listening;    //开始监听是否有客户端连接。    if(listen(Listening,40) == SOCKET_ERROR)    {        return 0;    }    char szBuf[MAX_PATH];    //初始化    memset(szBuf,0,MAX_PATH);    while(1)    {        SOCKET ConnectSocket;        sockaddr_in ClientAddr;        int nLen = sizeof(sockaddr);        //阻塞直到有客户端连接,不然多浪费CPU资源。        ConnectSocket = accept(Listening,(sockaddr*)&ClientAddr,&nLen);        //得到客户端的IP地址。        char *pAddrname = inet_ntoa(ClientAddr.sin_addr);        pDlg->Receive(ConnectSocket,szBuf,100);        //界面上显示请求数据。        pDlg->SetRequestText(szBuf);        strcat(szBuf, " :我是老猫,收到(");        strcat(szBuf, pAddrname);        strcat(szBuf, "");        //向客户端发送回应数据        pDlg->Send(ConnectSocket,szBuf,100);    }    return 0;}

       服务器端一直在监听是否有客户端连接,如有连接,处理客户端的请求,给出回应,然后继续监听。

  客户端:

  客户端的发送函数:

#define DEFAULT_PORT 2000void CClientDlg::OnSend(){       DWORDdwIP = 0;             TCHAR szText[MAX_PATH];       memset(szText, 0, MAX_PATH);       m_IP.GetWindowText(szText, MAX_PATH);       //把字符串形式的IP地址转成IN_ADDR结构需要的形式。       dwIP = inet_addr(szText);       m_RequestEdit.GetWindowText(szText, MAX_PATH);        sockaddr_in local;       SOCKET socketTmp;       //必须是AF_INET,表示该socket在Internet域中进行通信       local.sin_family = AF_INET;       //端口号       local.sin_port = htons(DEFAULT_PORT);       //服务器的IP地址。       local.sin_addr.S_un.S_addr = dwIP;             ////初始化Socket       socketTmp = socket(AF_INET, SOCK_STREAM, 0);       //连接服务器       if(connect(socketTmp, (LPSOCKADDR) & local, sizeof(local)) < 0)       {              closesocket(socketTmp);              MessageBox("连接服务器失败。");              return ;       }       //发送请求,为简单只发100字节,在服务器端也规定100字节。       Send(socketTmp, szText, 100);       //读取服务器端返回的数据。       memset(szText,0,MAX_PATH);       //接收服务器端的回应。       Receive(socketTmp, szText, 100);        TCHAR szMessage[MAX_PATH];       memset(szMessage, 0, MAX_PATH);       strcat(szMessage, szText);       //界面上显示回应数据。       m_ReplyBtn.SetWindowText(szMessage);       closesocket(socketTmp);}

       客户端就一个函数完成了一次通信。在这里IP地址为何用127.0.0.1呢?使用这个IP地址,服务器端和客户端就能运行在同一台机器上,这样调试方便多了。当然你可以在你朋友的机器上运行Server程序(本人在局域网中测试过),在自己的机器上运行Client程序,当然输入的IP地址就该是你朋友机器的IP地址了。

       简单的理论和实践都说了,现在Socket编程不神秘了吧?希望对你有些帮助。     

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 蓝河奶粉宝宝吃了不长肉怎么办 苹果ios版本太低激活不了怎么办 脸上被油烫伤了 起了水泡怎么办 皮肤被油烫伤起来个水泡怎么办 去泰国旅游没来得及兑换泰铢怎么办 游戏和安卓 不和 出现黑屏怎么办 邻居把垃圾放在楼梯口不丢怎么办 58热敏小票打印机口松了怎么办 王鹏的眼睛今天起疙瘩了怎么办 背包带子老从肩膀滑下来怎么办 绝地求生用手机流量更新不成怎么办 手机拍的视频在电脑上放不了怎么办 炉石传说手机点登陆游戏闪退怎么办 车到信号屏蔽区一键启动不了怎么办 王者荣耀战队活跃度满了怎么办 win10你的账户已被停用怎么办 电脑一键还原后一直黑屏怎么办? 被打了狂犬疫苗的狗咬伤怎么办 美版苹果7系统坏了怎么办 韩服的球球大作战网络不稳定怎么办 球球大作战号删了找不回来怎么办 队友传足球球的时候接不到怎么办 魅族手机中病毒锁机了怎么办? vbs打开是和文本文档一样怎么办 把电脑注册表删了电脑动不了怎么办 注册表删一项后电脑启动不了怎么办 解压过的过的软件安装包损坏怎么办 手机中病毒自动发短信扣费怎么办 苹果手机中的高德地图打不开怎么办 大晚上挂了别人的车怎么办 手机不兼容高版本微信怎么办 绝地求生右下角小地图变大了怎么办 杯孕当月做了C丁怎么办 玩全军出击手机发烫就出现卡怎么办 不小心买了彩虹六号肝帝版本怎么办 微信游戏刺激战场电脑卡怎么办 电脑更新了以前的东西都没了怎么办 安装黑苹果鼠标键盘不能用怎么办 苹果开机卡在白底黑苹果怎么办 信长之野望14没有剧情触发怎么办 玩cf手游手机屏幕摩擦力大怎么办