Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Socket编程

Socket编程

作者头像
jack.yang
发布于 2025-04-05 05:43:32
发布于 2025-04-05 05:43:32
1210
举报

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

1.         什么是TCP/IP、UDP? 2.         Socket在哪里呢? 3.         Socket是什么呢? 4.         你会使用它们吗?

在回答大家这些问题前请大家回顾一下大学网络课程学到七层模型知识,我在这里贴一张科来公司(http://www.colasoft.com.cn/)总结网络图给大家参考

什么是TCP/IP、UDP?

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。 UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。         这里有一张图,表明了这些协议的关系。

                                                                        图1

       TCP/IP协议族包括运输层、网络层、链路层。现在你知道TCP/IP与UDP的关系了吧。 Socket在哪里呢? 在图1中,我们没有看到Socket的影子,那么它到底在哪里呢?还是用图来说话,一目了然。

图2

       原来Socket在这里。 Socket是什么呢? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。 你会使用它们吗? 前人已经给我们做了好多的事了,网络间的通信也就简单了许多,但毕竟还是有挺多工作要做的。以前听到Socket编程,觉得它是比较高深的编程知识,但是只要弄清Socket编程的工作原理,神秘的面纱也就揭开了。        一个生活中的场景。你要打电话给一个朋友,先拨号,朋友听到电话铃声后提起电话,这时你和你的朋友就建立起了连接,就可以讲话了。等交流结束,挂断电话结束此次交谈。    生活中的场景就解释了这工作原理,也许TCP/IP协议族就是诞生于生活中,这也不一定。

图3

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

void CServerDlg::OnStart()

{

       sockaddr_in local;

       DWORD dwThreadID = 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      2000

void CClientDlg::OnSend()

{

       DWORD dwIP = 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地址了。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2009-02-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
R tips: ggplot图层编写
在实际使用中,ggplot中使用的图层是以geom或者stat开头的函数创建的,但是如果查看一下这些图层函数的具体内容可以发现他们都是在封装一个layer函数。
生信菜鸟团
2023/09/08
3700
R tips: ggplot图层编写
ggplot2都有哪些使用不多但是却异常强大的图层函数
要说ggplot2中那些使用不多但是却功能强大的图层函数,我首先想到的就是geom_rect、geom_linerange、geom_segment、geom_ploygon。
数据小磨坊
2018/07/25
1.9K0
ggplot2都有哪些使用不多但是却异常强大的图层函数
🤒 geomtextpath | 成功让你的ggplot注释拥有傲人曲线!~
1写在前面 最近的世界杯结果的确是让人大跌眼镜🕶️, 日本队🇯🇵先后击败世界杯冠军, 德国队🇩🇪和西班牙队🇪🇸, 韩国队🇰🇷逆转葡萄牙🇵🇹, 踩着乌拉圭🇺🇾进入淘汰赛(请韩国队🇰🇷自觉感谢裁判), 让无数人站上天台😂. 不过大家要是看看这几十年日本足球⚽️的发展也就不会觉得奇怪了, 就算有一天日本队将梦想照进现实,捧起大力神杯🏆, 我也不觉得有什么奇怪的. 还是祝各亚洲球队取得好成绩, 也祝梅西和C罗在顶峰相遇, 人生不留遗憾😘. ---- 接着是这一期的教程, 最近用了一下geomtextpath, 是个
生信漫卷
2023/02/24
4070
🤒 geomtextpath | 成功让你的ggplot注释拥有傲人曲线!~
106-R可视化30-底层绘图系统grid学习之重头创建ggplot对象之一
虽然ggplot2 和它的朋友们[[xx-R可视化30-ggplot又一拓展包之ggforce]], [[xx-R可视化xx-用ggalt体验ggplot新版DLC(拓展)]] 给我们提供了大量绘图的选项。比如通过操纵 geom_** 和stat_** 函数。
北野茶缸子
2022/04/05
8680
106-R可视化30-底层绘图系统grid学习之重头创建ggplot对象之一
ggplot2|详解八大基本绘图要素
ggplot2是由Hadley Wickham创建的一个十分强大的可视化R包。按照ggplot2的绘图理念,Plot(图)= data(数据集)+ Aesthetics(美学映射)+ Geometry(几何对象)。本文将从ggplot2的八大基本要素逐步介绍这个强大的R可视化包。
生信补给站
2020/08/05
7.5K0
ggplot2|详解八大基本绘图要素
ggplot2绘制logo版环状条形图
R语言数据分析指南
2023/09/11
4020
ggplot2绘制logo版环状条形图
R语言ggplot2画漂亮的环形柱形图的一个实例
代码来源的链接是 https://github.com/NearAndDistant/data_science_with_r
用户7010445
2022/02/21
1.3K0
R语言ggplot2画漂亮的环形柱形图的一个实例
ggplot2优雅绘制环状华夫图
❝本节来介绍如何只使用「geom_segment」函数来绘制环状华夫图,这个名称也许更符合示例图表,「数据代码已经上传VIP群,请自行下载」 ❞ 加载R包 library(tidyverse) library(ggtext) 导入数据 df <- read_tsv("data.xls") %>% mutate(count =as.factor(EDA_count)) labels <- tibble(x = 0,y = 1:5, text = c("A", "B","C","D","E")) 数
R语言数据分析指南
2022/09/23
3260
ggplot2优雅绘制环状华夫图
跟着Nature学作图:R语言ggplot2环形堆积柱形图完整示例
https://www.nature.com/articles/s41586-022-04664-7#Sec33
用户7010445
2023/01/06
3.2K0
跟着Nature学作图:R语言ggplot2环形堆积柱形图完整示例
ggplot2优雅的自定义轴文本颜色
❝今天来主要介绍如何在不引入外部几何对象的前提下在图形的原有的基础上「自定义修改轴文本颜色」,也许恰好您正好有此特殊需求,希望对各位观众老爷有所帮助;下面来看具体案例; ❞ 加载R包 library(tidyverse) 数据清洗 data1 <- mtcars %>% head(6) %>% mutate_if(is.numeric, function(x) x+10) %>% log10() %>% as.data.frame() %>% rownames_to_column("ty
R语言数据分析指南
2022/09/21
1.5K0
ggplot2优雅的自定义轴文本颜色
R语言ggplot2每周一图活动第五周:箱线图、小提琴图
在之前提到的tidytuesday里没有找到关于箱线图和小提琴图比较好的实例,这周的ggplot2每周一图活动用之前推文中的内容作为实例进行讲解,之前的推文是跟着Nature学作图:R语言ggplot2箱线图、小提琴图、抖动散点图
用户7010445
2022/05/23
6970
R语言ggplot2每周一图活动第五周:箱线图、小提琴图
跟着Nature学作图:R语言ggplot2箱线图、小提琴图、抖动散点图
https://github.com/GRONINGEN-MICROBIOME-CENTRE/DMP
用户7010445
2022/05/23
5.8K0
跟着Nature学作图:R语言ggplot2箱线图、小提琴图、抖动散点图
用ggplot2画了一个我也叫不上名的炫酷图表
今日心血来潮,看到一幅制作精良的图表,就想使用ggplot2代码实现,虽然不知道该怎么称呼这个图表,但是能顺利做出来也是很有成就感的! 加载数据包 library("ggplot2") library("grid") library("showtext") library("Cairo") font.add("myfont","msyh.ttc") 构造图形数据源 mydata<-data.frame( id=1:13, class=rep_len(1:4, length=13), Label=c("Eve
数据小磨坊
2018/04/11
1K0
用ggplot2画了一个我也叫不上名的炫酷图表
R语言ggplot2漂亮的热图和配色简单小例子
偶然间在github 上发现的这个链接,示例数据和代码都有,很好的R语言学习素材 链接是 https://github.com/blmoore/blogR ,主要内容有 image.png 光看这个可
用户7010445
2021/04/21
8.4K0
R语言ggplot2漂亮的热图和配色简单小例子
ggplot2修改坐标轴详细介绍
ggplot2的每个细节都是可以修改的,非常推荐大家系统学习一下,用到再学确实是一种不错的方式,但是如果要提高进阶,还是有必要系统学习的。
医学和生信笔记
2022/11/15
12.2K0
ggplot2修改坐标轴详细介绍
108-R可视化32-通过seurat包中的LabelClusters学习ggplot之一
在先前的内容里:[[66-R可视化10-自由的在ggplot上添加文本(柱状图加计数)]],我们提到过添加文本的方法。但是,对于散点图来说,我们需要找到的是一个坐标,而这个坐标,最好可以反映位置散点的中心或附近区域,对这个坐标进行标识。
北野茶缸子
2022/04/05
1.1K0
108-R可视化32-通过seurat包中的LabelClusters学习ggplot之一
(数据科学学习手札38)ggplot2基本图形简述
  上一篇中我们介绍了ggplot2的基本语法规则,为了生成各种复杂的叠加图层,需要了解ggplot2中一些基本的几何图形的构造规则,本文便就常见的基础几何图形进行说明;
Feffery
2018/05/30
5.5K10
医信融合创新沙龙投稿-圆形柱状图(富集圈图)
我们使用df <- df[-which(df$fraction < 0.03),]去掉部分或用AI处理.
叶子Tenney
2023/03/07
6890
医信融合创新沙龙投稿-圆形柱状图(富集圈图)
高阶可视化绘图系统:ggplot2入门
ggplot2是《The Grammar of Graphics》/《图形的语法》中提出了一套图形语法,将图形元素抽象成可以自由组合的要素,类似Photoshop中的图层累加,ggplot2将指定的元素/映射关系逐层叠加,最终形成所图形。更加深入学习ggplot2,请参考《ggplot2: 数据分析与图形艺术》。
1480
2019/07/22
1.8K0
高阶可视化绘图系统:ggplot2入门
是Excel的图,不!是R的图
excel作为一个强大的统计工具,自身包含着一部分数据可视化的功能。R作为可视化的大势,自然也可以画出这些图,有一篇就通过ggplot2包进行了部分总结,甚是有趣,小编复刻学习了一番,现对代码做简单注释,以作分享。
生信宝典
2019/08/01
4.3K0
是Excel的图,不!是R的图
推荐阅读
相关推荐
R tips: ggplot图层编写
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档