如何进行网络编程(网络编程实现)

http://www.itjxue.com  2023-02-28 15:13  来源:未知  点击次数: 

即时通讯软件开发的网络编程方式有哪些?

引言、即时通讯是网上最为流行的通讯方式,市场上也出现了各种各样的即时通讯软件。这篇文章将会给大家介绍一些开发即时通讯软件的网络编程方式。

一、什么是即时通讯。

即时通讯就是可以随时随地发送和接收信息,简单来说,即时通讯就是聊天工具。生活中常见的即时通讯工具有微信、QQ等。

二、即时通讯软件开发的网络编程方式都有哪些?

开发即时通讯软件需要用到安卓端技术java语言,苹果端oc语言,电脑端win系统桌面C/C++语言,管理后台数据库语言,后台管理界面java或者php。建议可以使用第三方SDK,可以有效地避免消息漏发,卡顿,数据并发等很多问题,提高了用户对产品的体验感。

三、如何设置编程。

mysql数据库的用户名为root,密码为空,可以根据自己的需要设置相应的用户名和密码(固定在程序中)。mychatserver是聊天服务器,myfileserver是文件服务器,文件服务器负责上传和下载聊天中发送的文件,myimgserver负责上传和下载聊天中的图片。三个服务之间相互独立,不会互相影响。聊天服务器监听端口是20000,文件服务器端口是20001,图片服务器端口号是20002,这三个端口的客户端连接,其中聊天端口和客户端是长连接,文件端口和图片可选择长连接或短连接。第一次运行mychatserver时,如果能顺利连上mysql,mychatserver会自动检测是否存在名为myim的数据库,如果不存在就可以创建了,并新建三张信息表,分别是用户信息表,好友关系表和聊天消息记录表。第一次启动文件服务器时会创建filecache目录,这个目录用来存储聊天中的聊天图片和离线文件以及客户端的升级包。为了方便查看代码,可以用Visual Studio管理代码,使用VS打开myserver.sln查看和管理代码。

如何学习网络编程

1.利用WinInet函数库写了几个简单的网络应用程序:简易登录、查询新书RSS等;了解了HTTP协议的一些内容。

2.看孙鑫的VC视频教程, ,虽然照着视频能够写出实例代码来,但是仅仅是会用,其中很多原理都不理解,比如说WSA开头的异步函数,Winsock2对socket的一些增强或者改进等。

3.一边上《计算机网络》的课,一边读《C++网络编程》。通过计算机网络课我知道了所谓的协议分析是怎么一回事情,通过wireshark抓包分析,“协议”就如同这个词本身意思是一样的,是通信过程中的一种约定,规定了数据包中的每个或每几个字节代表了什么意思;

4.去看《计算机网络高级编程技术》,我初略的翻了翻,看到里面的基础、提高、综合训练篇、突然反应过来:socket和操作系统提供的系统调用,基本上都是C语言接口的,协议字段的具体表现,不就是用结构体吗?协议中的几个字节代表什么与C语言基本数据类型就能对应了起来(-_-!这是缺少实践造成的迟钝啊)。

5.了解下Boost.asio,Java的MINA框架,这些都是异步I/O前摄器模式的实现,当然还有ACE_Proactor

6.阅读《深入理解MySQL核心技术》和Linux程序设计(第3版)》,从把整个知识体系都联系起来,从socket到完整网络服务器程序,网络编程才算正式进入了门道。

所以,正常的学习路径应该是:C/C++语言 --计算机网络 --协议分析 --BSD Socket、OS API ( fork()、pthread_create()、select() ) --Reactor、Proactor模式

在这个过程我的体会是,最好是从Linux下或者Unix底下学习,比起Windows,Linux的编程接口设计更很简洁,使用的基本上都是标准的数据类型,很多源代码是开放的,而且我比较习惯于看小写的英文单词。。。我发现,如果最一开始能够从整体上了解网络编程的全景,就会知道应该学习什么,下一步该学什么,循序渐进才是好的学习方法。

我所理解的“全景”:

--计算机网络种类有很多种:ATM、X.25、Internet(大大小小的局域网互联而成,以太网、令牌网等等)

---- Internet通信的协议也有很多种,其中最核心的是TCP/IP协议

---- 网络编程接口也有很多种,BSD UNIX提出了socket,是一种通信机制,是管道概念的扩展

-------- socket有三种属性:域(或协议族)、类型、协议

-------- 最常用的协议族有AF_UNIX和AF_INET(对应现在的Internet),AF_INET的类型又有两种:数据流(tcp)和数据报 (udp)

------------ 在sys/types.h和sys/socket.h定义了socket编程的系统调用:socket()、struct sockaddr、bind()、listen()、accept()、connect()、close()、sendto()、recvfrom()

------------ 其中bind()是用来给创建的socket命名的,如果是AF_UNIX会关联到文件系统的一个路径上,如果是AF_INET则会绑定到IP的端口号上;listen()用来保存未处理的客户请求的队列;accept()等待客户端的连接,会创建新的socket用来处理客户端连接。

------------ 由于历史原因,不同的计算机使用不同的字节序来表示整数,Intel和Motorola的处理器的字节序就不一样,所以要转换为网络序(好像Unicode中的Little-Endian、Big-Endian也是这么个情况。。)

------------ 服务器必然为多客户服务的,为了提高运行效率,高效利用系统资源,就出现多进程、多线程的服务端程序,这就需要用到fork()和pthread_create()了,再往下就是select()、pull()等多路复用和异步I/O机制了。

----------------为了简化网络应用程序的开发,增加代码的复用性、扩展性、可谓性;出现了Reacotr、Preactor等设计模式,出现了ACE、Boost.asio等框架、进一步简化网络开发的难度,出现了WinInet、libcurl这样的面向应用层的函数库。

网络编程(五)TCP详解

考虑最简单的情况:两台主机之间的通信。这个时候只需要一条网线把两者连起来,规定好彼此的硬件接口,如都用 USB、电压 10v、频率 2.4GHz 等, 这一层就是物理层,这些规定就是物理层协议 。

我们当然不满足于只有两台电脑连接,因此我们可以使用交换机把多个电脑连接起来,如下图:

这样连接起来的网络,称为局域网,也可以称为以太网(以太网是局域网的一种)。在这个网络中,我们需要标识每个机器,这样才可以指定要和哪个机器通信。这个标识就是硬件地址 MAC。

硬件地址随机器的生产就被确定,永久性唯一。在局域网中,我们需要和另外的机器通信时,只需要知道他的硬件地址,交换机就会把我们的消息发送到对应的机器。

这里我们可以不管底层的网线接口如何发送,把物理层抽离,在他之上创建一个新的层次,这就是 数据链路层 。

我们依然不满足于局域网的规模,需要把所有的局域网联系起来,这个时候就需要用到路由器来连接两个局域网:

但是如果我们还是使用硬件地址来作为通信对象的唯一标识,那么当网络规模越来越大,需要记住所有机器的硬件地址是不现实的;

同时,一个网络对象可能会频繁更换设备,这个时候硬件地址表维护起来更加复杂。这里使用了一个新的地址来标记一个网络对象: IP 地址 。

通过一个简单的寄信例子来理解 IP 地址。

我住在北京市,我朋友 A 住在上海市,我要给朋友 A 写信:

因此,这里 IP 地址就是一个网络接入地址(朋友 A 的住址),我只需要知道目标 IP 地址,路由器就可以把消息给我带到。 在局域网中,就可以动态维护一个 MAC 地址与 IP 地址的映射关系,根据目的 IP 地址就可以寻找到机器的 MAC 地址进行发送 。

这样我们不需管理底层如何去选择机器,我们只需要知道 IP 地址,就可以和我们的目标进行通信。这一层就是 网络层 。网络层的核心作用就是 提供主机之间的逻辑通信 。

这样,在网络中的所有主机,在逻辑上都连接起来了,上层只需要提供目标 IP 地址和数据,网络层就可以把消息发送到对应的主机。

一个主机有多个进程,进程之间进行不同的网络通信,如边和朋友开黑边和女朋友聊微信。我的手机同时和两个不同机器进行通信。

那么当我的手机收到数据时,如何区分是微信的数据,还是王者的数据?那么就必须在网络层之上再添加一层: 运输层 :

运输层通过 socket(套接字),将网络信息进行进一步的拆分,不同的应用进程可以独立进行网络请求,互不干扰。

这就是运输层的最本质特点: 提供进程之间的逻辑通信 。这里的进程可以是主机之间,也可以是同个主机,所以在 android 中,socket 通信也是进程通信的一种方式。

现在不同的机器上的应用进程之间可以独立通信了,那么我们就可以在计算机网络上开发出形形式式的应用:如 web 网页的 http,文件传输 ftp 等等。这一层称为 应用层 。

应用层还可以进一步拆分出表示层、会话层,但他们的本质特点都没有改变: 完成具体的业务需求 。和下面的四层相比,他们并不是必须的,可以归属到应用层中。

最后对计网分层进行小结:

这里需要注意的是,分层并不是在物理上的分层,而是逻辑上的分层。通过对底层逻辑的封装,使得上层的开发可以直接依赖底层的功能而无需理会具体的实现,简便了开发。

这种分层的思路,也就是责任链设计模式,通过层层封装,把不同的职责独立起来,更加方便开发、维护等等。

TCP 并不是把应用层传输过来的数据直接加上首部然后发送给目标,而是把数据看成一个字节 流,给他们标上序号之后分部分发送。这就是 TCP 的 面向字节流 特性:

面向字节流的好处是无需一次存储过大的数据占用太多内存,坏处是无法知道这些字节代表的意义,例如应用层发送一个音频文件和一个文本文件,对于 TCP 来说就是一串字节流,没有意义可言,这会导致粘包以及拆包问题,后面讲。

前面讲到,TCP 是可靠传输协议,也就是,一个数据交给他,他肯定可以完整无误地发送到目标地址,除非网络炸了。他实现的网络模型如下:

对于应用层来说,他就是一个可靠传输的底层支持服务;而运输层底层采用了网络层的不可靠传输。虽然在网络层甚至数据链路层就可以使用协议来保证数据传输的可靠性,但这样网络的设计会更加复杂、效率会随之降低。把数据传输的可靠性保证放在运输层,会更加合适。

可靠传输原理的重点总结一下有: 滑动窗口、超时重传、累积确认、选择确认、连续 ARQ 。

停止等待协议

要实现可靠传输,最简便的方法就是:我发送一个数据包给你,然后你跟我回复收到,我继续发送下一个数据包。传输模型如下:

这种“一来一去”的方法来保证传输可靠就是 停止等待协议 (stop-and-wait)。不知道还记不记得前面 TCP 首部有一个 ack 字段,当他设置为 1 的时候,表示这个报文是一个确认收到报文。

然后再来考虑另一种情况:丢包。网络环境不可靠,导致每一次发送的数据包可能会丢失,如果机器 A 发送了数据包丢失了,那么机器 B 永远接收不到数据,机器 A 永远在等待。

解决这个问题的方法是: 超时重传 。当机器 A 发出一个数据包时便开始计时,时间到还没收到确认回复,就可以认为是发生了丢包,便再次发送,也就是重传。

但重传会导致另一种问题:如果原先的数据包并没有丢失,只是在网络中待的时间比较久,这个时候机器 B 会受到两个数据包,那么机器 B 是如何辨别这两个数据包是属于同一份数据还是不同的数据?

这就需要前面讲过的方法: 给数据字节进行编号 。这样接收方就可以根据数据的字节编号,得出这些数据是接下来的数据,还是重传的数据。

在 TCP 首部有两个字段:序号和确认号,他们表示发送方数据第一个字节的编号,和接收方期待的下一份数据的第一个字节的编号。

停止等待协议的优点是简单,但缺点是 信道利用率 太低。

假定AB之间有一条直通的信道来传送分组

这里的TD是A发送分组所需要的时间(显然TD = 分组长度 / 数据速率)再假定TA是B发送确认分组所需要的时间(A和B处理分组的时间都忽略不计)那么A在经过TD+RTT+TA时间后才能发送下一个分组,这里的RTT是往返时间,因为只有TD是采用来传输有用的数据(这个数据包括了分组首部,如果可以知道传输更精确的数据的时间,可以计算的更精确),所有信道利用率为

为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用 流水线传输 :就是发送方可以 连续的发送多个分组 ,不必每发完一个分组就停下来等待对方的确认。这样可使信道上一直有数据不间断地在传送。显然这种传输方式可以获得很高的信道利用率

停止等待协议已经可以满足可靠传输了,但有一个致命缺点: 效率太低 。发送方发送一个数据包之后便进入等待,这个期间并没有干任何事,浪费了资源。解决的方法是: 连续发送数据包 。

也就是下面介绍的 连续ARQ协议 和 滑动窗口协议

连续 ARQ 协议

模型如下:

和停止等待最大的不同就是,他会源源不断地发送,接收方源源不断收到数据之后,逐一进行确认回复。这样便极大地提高了效率。但同样,带来了一些额外的问题:

发送是否可以无限发送直到把缓冲区所有数据发送完?不可以。因为需要考虑接收方缓冲区以及读取数据的能力。如果发送太快导致接收方无法接受,那么只是会频繁进行重传,浪费了网络资源。所以发送方发送数据的范围,需要考虑到接收方缓冲区的情况。这就是 TCP 的 流量控制 。

解决方法是: 滑动窗口 。基本模型如下:

在 TCP 的首部有一个窗口大小字段,他表示接收方的剩余缓冲区大小,让发送方可以调整自己的发送窗口大小。通过滑动窗口,就可以实现 TCP 的流量控制,不至于发送太快,导致太多的数据丢失。

连续 ARQ 带来的第二个问题是:网络中充斥着和发送数据包一样数据量的确认回复报文,因为每一个发送数据包,必须得有一个确认回复。提高网络效率的方法是: 累积确认 。

接收方不需要逐个进行回复,而是累积到一定量的数据包之后,告诉发送方,在此数据包之前的数据全都收到。例如,收到 1234,接收方只需要告诉发送方我收到 4 了,那么发送方就知道 1234 都收到了。

第三个问题是:如何处理丢包情况。在停止等待协议中很简单,直接一个超时重传就解决了。但,连续 ARQ 中不太一样。

例如:接收方收到了 123 567,六个字节,编号为 4 的字节丢失了。按照累积确认的思路,只能发送 3 的确认回复,567 都必须丢掉,因为发送方会进行重传。这就是 GBN(go-back-n) 思路。

但是我们会发现,只需要重传 4 即可,这样不是很浪费资源,所以就有了: 选择确认 SACK 。在 TCP 报文的选项字段,可以设置已经收到的报文段,每一个报文段需要两个边界来进行确定。这样发送方,就可以根据这个选项字段只重传丢失的数据了。

第四个问题是:拥塞控制的问题

也是通过窗口的大小来控制的,但是检测网络满不满是个挺难的事情,所以 TCP 发送包经常被比喻成往谁管理灌水,所以拥塞控制就是在不堵塞,不丢包的情况下尽可能的发挥带宽。

水管有粗细,网络有带宽,即每秒钟能发送多少数据;水管有长度,端到端有时延。理想状态下,水管里面的水 = 水管粗细 * 水管长度。对于网络上,通道的容量 = 带宽 * 往返时延。

如果我们设置发送窗口,使得发送但未确认的包为通道的容量,就能撑满整个管道。

如图所示,假设往返时间为 8 秒,去 4 秒,回 4 秒,每秒发送一个包,已经过去了 8 秒,则 8 个包都发出去了,其中前四个已经到达接收端,但是 ACK 还没返回,不能算发送成功,5-8 后四个包还在路上,还没被接收,这个时候,管道正好撑满,在发送端,已发送未确认的 8 个包,正好等于带宽,也即每秒发送一个包,也即每秒发送一个包,乘以来回时间 8 秒。

如果在这个基础上调大窗口,使得单位时间可以发送更多的包,那么会出现接收端处理不过来,多出来的包会被丢弃,这个时候,我们可以增加一个缓存,但是缓存里面的包 4 秒内肯定达不到接收端课,它的缺点会增加时延,如果时延达到一定程度就会超时重传

TCP 拥塞控制主要来避免两种现象,包丢失和超时重传,一旦出现了这些现象说明发送的太快了,要慢一点。

具体的方法就是发送端慢启动,比如倒水,刚开始倒的很慢,渐渐变快。然后设置一个阈值,当超过这个值的时候就要慢下来

慢下来还是在增长,这时候就可能水满则溢,出现拥塞,需要降低倒水的速度,等水慢慢渗下去。

拥塞的一种表现是丢包,需要超时重传,这个时候,采用快速重传算法,将当前速度变为一半。所以速度还是在比较高的值,也没有一夜回到解放前。

到这里关于 TCP 的可靠传输原理就已经介绍得差不多。最后进行一个小结:

当然,这只是可靠传输的冰山一角,感兴趣可以再深入去研究

如何用MFC实现网络编程

?????一.?客户端?

?????1.?创建一个Dialog?Based项目:CSockClient。?

?????2.?设计对话框?

?????去掉Ok和Cancle两个按钮,增加ID_Connect(连接)、ID_Send(发送)、ID_Exit(关闭)按钮,增加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,并按下表在ClassWizard中为CCSockClientDlg类添加变量。?

?????Control?ID?????Type?????????Member

?????IDC_EDITMSG????CEdit???????m_MSG

?????IDC_LISTMSG????ClistBox????m_MSGS

?????3.?CAsyncSocket类用DoCallBack函数处理MFC消息,当一个网络事件发生时,DoCallBack函数按网络事件类型:FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT分别调用OnReceive、OnSend、OnAccept、OnConnect函数。

?????由于MFC把这些事件处理函数定义为虚函数,所以要生成一个新的C++类,以重载这些函数,做法如下:以Public方式继承CAsyncSocket类,生成新类MySock;为MySock类添加虚函数OnReceive、OnConnect、OnSend。?

?????4.?在MySock.ccp中添加以下代码?

?????#include?"CSockClient.h"

?????#include?"CSockClientDlg.h"

?????5.?在MySock.h中添加以下代码?

?????public:

?????BOOL?m_bConnected;????//是否连接

?????UINT?m_nLength;????//消息长度

?????char?m_szBuffer[4096];?//消息缓冲区

?????6.?在MySock.ccp中重载各函数?

?????MySock::MySock()

?????{

?????????m_nLength=0;

?????????memset(m_szBuffer,0,sizeof(m_szBuffer));

?????????m_bConnected=FALSE;

?????}

?????MySock::~MySock()

?????{

?????????//关闭套接字

?????if(m_hSocket!=INVALID_SOCKET)

?????Close();

?????}

?????void?MySock::OnReceive(int?nErrorCode)?

?????{

?????????m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);

?????????//下面两行代码用来获取对话框指针

?????CCSockClientApp*?pApp=(CCSockClientApp*)AfxGetApp();

?????????CCSockClientDlg*?pDlg=(CCSockClientDlg*)pApp-?m_pMainWnd;

?????????pDlg-?m_MSGS.InsertString(0,m_szBuffer);

?????????memset(m_szBuffer,0,sizeof(m_szBuffer));

?????????CAsyncSocket::OnReceive(nErrorCode);

?????}

?????void?MySock::OnSend(int?nErrorCode)?

?????{

?????????Send(m_szBuffer,m_nLength,0);

?????????m_nLength=0;

?????????memset(m_szBuffer,0,sizeof(m_szBuffer));

?????????//继续提请一个“读”的网络事件,接收Server消息

?????AsyncSelect(FD_READ);

?????????CAsyncSocket::OnSend(nErrorCode);

?????}

?????void?MySock::OnConnect(int?nErrorCode)?

?????{

?????????if?(nErrorCode==0)

?????????{

?????m_bConnected=TRUE;

?????CCSockClientApp*?pApp=(CCSockClientApp*)AfxGetApp();

?????CCSockClientDlg*?pDlg=(CCSockClientDlg*)pApp-?m_pMainWnd;

?????memcpy(m_szBuffer,"Connected?to?",13);

?????strncat(m_szBuffer,pDlg-?m_szServerAdr,

?????sizeof(pDlg-?m_szServerAdr));

?????pDlg-?m_MSGS.InsertString(0,m_szBuffer);

?????AsyncSelect(FD_READ);?////提请一个“读”的网络事件,准备接收

?????????}

?????????CAsyncSocket::OnConnect(nErrorCode);

?????}

?????7.?新建对话框IDD_Addr,用来输入IP地址和Port;生成新类CAddrDlg。增加两个Edit控件:IDC_Addr、IDC_Port按下表在ClassWizard中为CAddrDlg类添加变量。?

?????Control?ID????Type????Member

?????IDC_Addr????CString????m_Addr

?????IDC_Port????Int????????m_Port

?????8.?在CSockClientDlg.ccp中添加代码:?

?????#include?"AddrDlg.h"

?????protected:

?????????int?TryCount;

?????????MySock?m_clientSocket;

?????????UINT?m_szPort;

?????public:

?????????char?m_szServerAdr[256];????

?????9.?双击IDD_CSOCKCLIENT_DIALOG对话框中的“连接”按钮,添加以下代码:?

?????void?CCSockClientDlg::OnConnect()?

?????{

?????????m_clientSocket.ShutDown(2);

?????????m_clientSocket.m_hSocket=INVALID_SOCKET;

?????????m_clientSocket.m_bConnected=FALSE;

?????????CAddrDlg?m_Dlg;

?????????//默认端口1088

?????m_Dlg.m_Port=1088;

?????????if?(m_Dlg.DoModal()==IDOK??!m_Dlg.m_Addr.IsEmpty())

?????????{

?????memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr));

?????m_szPort=m_Dlg.m_Port;

?????//建立计时器,每1秒尝试连接一次,直到连上或TryCount10

?????SetTimer(1,1000,NULL);

?????TryCount=0;

?????????}

?????}

?????10.?添加Windows消息WM_TIMER响应函数OnTimer?

?????void?CCSockClientDlg::OnTimer(UINT?nIDEvent)?

?????{

?????????if?(m_clientSocket.m_hSocket==INVALID_SOCKET)

?????????{

?????BOOL?bFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT);

?????if(!bFlag)

?????{

?????????AfxMessageBox("Socket?Error!");

?????????m_clientSocket.Close();

?????????PostQuitMessage(0);

?????????return;

?????}

?????????}

?????????m_clientSocket.Connect(m_szServerAdr,m_szPort);

?????????TryCount++;

?????????if?(TryCount?=10?||?m_clientSocket.m_bConnected)

?????????{????

?????KillTimer(1);

?????if?(TryCount?=10)

?????????AfxMessageBox("Connect?Failed!");

?????return;

?????????}

?????????CDialog::OnTimer(nIDEvent);

?????}

?????11.?双击IDD_CSOCKCLIENT_DIALOG对话框中的“发送”按钮,添加以下代码:?

?????void?CCSockClientDlg::OnSend()?

?????{

?????????if?(m_clientSocket.m_bConnected)

?????????{

?????m_clientSocket.m_nLength=m_MSG.GetWindowText

?????(m_clientSocket.m_szBuffer,?sizeof(m_clientSocket.m_szBuffer));

?????m_clientSocket.AsyncSelect(FD_WRITE);

?????m_MSG.SetWindowText("");

?????????}

?????}

?????12.?双击IDD_CSOCKCLIENT_DIALOG对话框中的“关闭”按钮,添加以下代码:?

?????void?CCSockClientDlg::OnExit()?

?????{

?????????//关闭Socket

?????m_clientSocket.ShutDown(2);

?????????//关闭对话框

?????EndDialog(0);????

?????}

?????12.运行此项目,连接时输入主机名或IP均可,CAsyncSocket类会自动处理。

?????二.?服务端

?????Server端的编程与Client端的类似,下面主要介绍他的Listen及Accept函数。

?????1.?建立一个CNewSocket类,重载CAsyncSocket类的OnReceive、OnSend函数,如何进行信息的显示和发送可以参考Client程序。本例中采用将收到信息原封不动发回的方法来实现Echo功能,代码如下:

?????CNewSocket::OnReceive(int?nErrorCOde)

?????{

?????????m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);

?????????//?直接转发消息

?????AsyncSelect(FD_WRITE);

?????}

?????CNewSocket::OnSend(int?nErrorCode)

?????{

?????????Send(m_szBuffer,m_nLength,0);

?????}

?????2.?建立一个CMyServerSocket类,重载CAsyncSocket类的OnAccept函数代码如下

?????在MyServerSocket.h中声明变量

?????public::

?????CNewSocket*?m_pSocket;

?????void?CMyServerSocket::OnAccept(int?nErrorCode)

?????{

?????????//侦听到连接请求,调用Accept函数

?????????CNewSocket*?pSocket?=?new?CNewSocket();

?????????if?(Accept(*pSocket))

?????????{

?????pSocket-?AsyncSelect(FD_READ);

?????m_pSocket=pSocket;

?????????}

?????????else

?????delete?pSocket;

?????}

?????3.?为对话框添加一个“侦听”按钮,添加如下代码:

?????在CsockServerDlg.ccp中声明变量

?????public:

?????????CMyServerSocket?m_srvrSocket;

?????void?CCSockServerDlg::OnListen()

?????{

?????????if?(m_srvrSocket.m_hSocket==INVALID_SOCKET)

?????????{

?????BOOL?bFlag=m_srvrSocket.Create

?????(UserPort,SOCK_STREAM,FD_ACCEPT);

?????if?(!bFlag)

?????{

?????????AfxMessageBox(“Socket?Error!”);

?????????M_srvrSocket.Close();

?????????PostQuitMessage(0);

?????????Return;

?????}

?????????}

?????//“侦听”成功,等待连接请求

?????if?(!m_srvrSocket。Listen(1))

?????{

?????int?nErrorCode?=?m_srvrSocket.GetLastError();

?????if?(nError!=WSAEWOULDBLOCK)

?????{

?????????AfxMessageBox(“Socket?Error!”);

?????????M_srvrSocket.Close();

怎样用C语言做socket网络编程?

mfc只是对socket进行了一些封装,大部分人做网络编程都是用的原始的socket,比如如下接口都可以在c下进行调用\x0d\x0a 1.socket() \x0d\x0a 2.bind() \x0d\x0a 3.connect() \x0d\x0a 4.listen() \x0d\x0a 5.accept() \x0d\x0a 6.send() 和recv() \x0d\x0a 7.sendto() 和recvfrom() \x0d\x0a 8.close() 和shutdown() \x0d\x0a 9.getpeername() \x0d\x0a 10.gethostname() \x0d\x0a这些接口是在Winsock2.h中定义的不是在mfc中定义的,你只需要包含Winsock2.h头文件和Ws2_32.lib库就可以了。

(责任编辑:IT教学网)

更多