Winsock程序设计入门

WinSock网络通信程序设计入门 对于许多初学者来说,网络通信程序的开发,普遍的一个现象就是觉得难以入手。许多概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)等,初学者往往迷惑不清,只知其所以而不知起所以然。  同步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而异步指发送方发出数据后,等收到接收方发回的响应,才发下一个数据包的通信方式。  阻塞套接字是指执行此套接字的 阅读详情

一、简单的TCP服务器


介绍

WinSock API是一套供Microsoft Windows操作系统使用的套接字程序库,它最初基于Berkeley套接字,但是其中加入了一些Microsoft的特殊改动。在这篇文章中,我要试着给你介绍如何使用WinSock来进行套接字程序设计,并假设你没有在任何操作系统上进行过网络编程的经验。
如果你只有一台单独的机器,那么不用着急,你仍然可以进行WinSock程序设计。你可以使用名为localhost的本地回环地址,它的IP地址是127.0.0.1。这样一来,如果你在机器上运行了一个TCP服务器,那么同一机器上的客户端程序就可以使用这个回环地址连接到服务器了。

简单的TCP服务器

在本文中,我将通过一个简单的TCP服务器来向你介绍WinSock,我们会一步一步地创建这个程序。但是,在我们开始之前,你还必须做一些事情,这样我们才能为开始我们的WinSock程序做好准备。
·首先,使用VC++ 6.0应用程序向导来创建一个Win32 console application。
·选择add support for MFC选项。
·打开stdafx.h文件,并添加这一行:#include <winsock2.h>。
·选择Project-Settings-Link,并在库模块列表中加入ws2_32.lib。

main函数

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    cout << "Press ESCAPE to terminate program/r/n";
    AfxBeginThread(ServerThread,0);
    while(_getch()!=27);

    return nRetCode;
}

我们在main()中所做的是开启一个线程,然后对一个_getch()调用进行循环。_getch()仅仅是等待一个键的按下,并返回这个读入字符的ASCII值。我们一直循环,直到返回27这个值为止——既然27是ESCAPE键的ASCII码。你可能想知道的是,即使我们按下了ESCAPE,我们开启的线程也还会是活动的状态。不用为这些事情担心,因为当main()返回的时候,进程就会被终止,主线程开启的线程也会被突然终止。

(我注:main是一个主线程,上面所讲的ServerThread是在主线程里开的一个守护线程,主线程开启一个守护线程后,任由守护线程去执行,main主线程还可以运行下去执行while(_getch()!=27)这句,当用户敲一个ESC键,就会接下去执行return nRetCode这句,进而main主线程结束,主线程结束后,守护线程就跟着结束了。另,在主线程里也可以开普通线程,普通线程不同于守护线程,main主线程在开普通线程处要停止运行下面的代码,而要等到普通线程执行完毕返回才接着执行main主线程后面的语句)

ServerThread函数

现在我所要做的事情就是把我们的ServerThread函数列出来,并使用代码的注释来解释相关的代码行做了些什么。我们的TCP服务器主要做的事情是监听端口20248,这个数字也就是我在Code Project的成员ID。这个过程中的事件是:当客户端连接的时候,服务器将会向客户端发回一条消息告知它的IP地址,然后关闭连接并继续接收20248端口的连接。它还会在运行的控制台上打印出连接来自的IP地址。总而言之,你可能会认为这是一个绝对没用的程序。事实上,你们中的有些人甚至可能会认为它和Windows中的SNDREC32.EXE一样没用。我说,你们也忒苛刻了吧。

UINT  ServerThread(LPVOID pParam)
{
    cout << "Starting up TCP server/r/n";

    // SOCKET其实是unsigned int的一个typedef。
    // 在Unix中,套接字句柄就像文件句柄一样,都是unsigned int。
    // 既然在Windows下这些不是真的,那么我们就定义了一种新的数据类型,名为SOCKET。
    SOCKET server;

    // WSADATA是一个struct,WSAStartup的调用将会填充之。
    WSADATA wsaData;

    // sockaddr_in为TCP/IP套接字指定了套接字的地址。
    // 其它的协议都使用相似的结构。
    sockaddr_in local;

    // WSAStartup为程序调用WinSock进行了初始化。
    // 第一个参数指定了程序允许使用的WinSock规范的最高版本。
    int wsaret=WSAStartup(0x101,&wsaData);

    // 如果成功,WSAStartup返回零。
    // 如果失败,我们就退出。
    if(wsaret!=0)
    {
        return 0;
    }

    // 现在我们来为sockaddr_in结构赋值。
    local.sin_family=AF_INET; // 地址族
    local.sin_addr.s_addr=INADDR_ANY; // 网际IP地址
    local.sin_port=htons((u_short)20248); // 使用的端口

    // 由socket函数创建我们的SOCKET。
    server=socket(AF_INET,SOCK_STREAM,0);

    // 如果socket()函数失败,我们就退出。
    if(server==INVALID_SOCKET)
    {
        return 0;
    }

    // bind将我们刚创建的套接字和sockaddr_in结构联系起来。
    // 它主要使用本地地址及一个特定的端口来连接套接字。
    // 如果它返回非零值,就表示出现错误。
    if(bind(server,(sockaddr*)&local,sizeof(local))!=0)
    {
        return 0;
    }

    // listen命令套接字监听来自客户端的连接。
    // 第二个参数是最大连接数。
    if(listen(server,10)!=0)
    {
        return 0;
    }

    // 我们需要一些变量来保存客户端的套接字,因此我们在此声明之。
    SOCKET client;
    sockaddr_in from;
    int fromlen=sizeof(from);

    while(true) // 无限循环
    {
        char temp[512];

        // accept()将会接收即将到来的客户端连接。
        client=accept(server,
            (struct sockaddr*)&from,&fromlen);

        sprintf(temp,"Your IP is %s/r/n",inet_ntoa(from.sin_addr));

        // 我们简单地向客户端发送这个字符串。
        send(client,temp,strlen(temp),0);
        cout << "Connection from " << inet_ntoa(from.sin_addr) <<"/r/n";

        // 关闭客户端套接字
        closesocket(client);

    }

    // closesocket()关闭套接字,并释放套接字描述符。
    closesocket(server);

    // 最初这个函数也许有些用处,现在保留它只是为了向后兼容。
    // 但是调用它可能会更安全,因为我相信某些实现会使用它来结束WS2_32.DLL的使用。
    WSACleanup();

    return 0;
}

测试

运行这个服务器,并在它运行的时候使用telnet来连接机器的20248端口。如果你是在同一台机器上使用,那么就连接到localhost。

示例输出

我们将会在服务器上看到这样的输出:

E:/work/Server/Debug>server
Press ESCAPE to terminate program
Starting up TCP server
Connection from 203.200.100.122
Connection from 127.0.0.1
E:/work/Server/Debug>

这是客户端得到的:

nish@sumida:~$ telnet 202.89.211.88 20248
Trying 202.89.211.88...
Connected to 202.89.211.88.
Escape character is '^]'.
Your IP is 203.200.100.122
Connection closed by foreign host.
nish@sumida:~$

总结

呃,在本文中你了解了如何创建一个简单的TCP服务器。在以后的文章中,我会给你一些更多的材料,你可以通过这些材料创建一个合适的TCP客户端。如果有谁对于编译这些代码有问题的话可以mail我,我会发给你一个压缩了的工程。谢谢您的阅读。

作者:Nishant S
原文链接:http://www.codeproject.com/internet/winsockintro02.asp
下载工程

二、简单的TCP客户端

介绍

本文是《Winsock程序设计入门(1) - 简单的TCP服务器》一文的结局,如果你还没有读过第1部分的话,我还是建议你首先读一下。在本文中,我将示范给你如何编写一个简单的TCP客户端程序。我们要编写一个程序,这个程序将连接到一个HTTP服务器,并获得一个文件。

一个简单的TCP客户端程序流程

1、使用WSAStartup()初始化WinSock库。
2、使用socket()创建一个IPPROTO_TCP SOCKET。
3、使用gethostbyname()/gethostbyaddr()获取主机信息。
4、使用connect()和我们创建的套接字连接服务器。
5、使用send()/recv()发送和接收数据,直到我们的TCP会话结束。
6、使用closesocket()关闭套接字连接。
7、使用WSACleanup()释放WinSock。

初始化WinSock

正如其它每个WinSock程序一样,我们需要初始化WinSock库。这也基本上是一种检查WinSock是否在当前系统可用的方法,对于以前的版本,我们当然希望是这样。

int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret)
    return;

创建SOCKET

套接字是一种实体,它担当了客户端和服务器之间的端点。当客户端连接到服务器之后,就会存在两个套接字——客户端一边的套接字和相应的服务器一边的套接字。让我们来称它们为CLIENTSOCK和SERVERSOCK。当客户端在CLIENTSOCK使用send()时,服务器可以在SERVERSOCK使用recv()来接收客户端所发送的数据,反之亦然。对于我们的目的,我们使用一个名为socket()的函数来创建套接字。

SOCKET conn;
conn=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(conn==INVALID_SOCKET)
    return;

获取主机信息

显然,我们在连接到主机(服务器)之前,要获取它的信息。我们可以使用两个函数——gethostbyname()和gethostbyaddr()。当我们拥有服务器的DNS名称时,我们可以使用gethostbyname()函数,例如codeproject.com或ftp.myserver.org之类的名称。当我们拥有要连接的服务器的IP地址时,可以使用gethostbyaddr()函数,例如192.168.1.1或202.54.1.100。
显然,我们希望能使我们的最终用户既能使用DNS名称,也能使用IP地址。那么,为了这些工作对他来说透明,我们需要像下面这样玩一个小把戏。我们对入口字符串使用inet_addr(),这个函数会把一个IP地址转换成一个标准的网络地址格式。这样一来,如果它返回失败,我们就可以知道这个字符串不是一个IP地址,如果它成功的话,我们就可以假设它是一个有效的IP地址了。

if(inet_addr(servername)==INADDR_NONE)
{
    hp=gethostbyname(servername);
}
else
{
    addr=inet_addr(servername);
    hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
    closesocket(conn);
    return;
}

连接到服务器

connect()函数用于向目标服务器建立连接。我们向它传递我们先前创建的套接字和一个sockaddr结构。我们使用由gethostbyname()/gethostbyaddr()返回的主机地址为sockaddr成员赋值,并输入一个要连接的有效端口。

server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(80);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
    closesocket(conn);
    return;
}

会话

当套接字连接建立后,客户端和服务器就可以通过send()和recv()来发送/接收数据了。这通常称为TCP会话。对于我们的特定情况,我们需要进行HTTP会话。和那些复杂的SMTP或POP3协议相比,它还是比较简单的。HTTP的GET命令用于从HTTP服务器上获取文件。这个文件可以是HTML文件、图像文件、压缩文件、MP3文件等等。这样,这个文件就会被发送了(这是它最简单的形式)。当然,还有一些更复杂的方法来使用这个命令。

GET http-path-to-file/r/n/r/n

在我们的程序中,我们像这样来发送GET命令:

sprintf(buff,"GET %s/r/n/r/n",filepath);
send(conn,buff,strlen(buff),0);

当我们发送了这个命令的时候,我们就应该知道服务器就要开始把我们所请求的文件发送给我们了。就像我们使用send()来发送我们的命令一样,我们可以使用recv()来接收服务器发送给我们的数据。我们循环调用recv(),直到它返回零,这时候我们就会知道服务器已经将数据发送完毕了。并且,对于我们的特定情况,我们可以将这些数据写入文件,就像我们要下载并保存这个文件一样。

while(y=recv(conn,buff,512,0))
{
    f.Write(buff,y);
}

关闭连接

现在我们的会话结束了,我们必须关闭连接。在我们的情况下,HTTP连接在文件发送完毕之后就会被服务器关闭了,但是这不要紧,我们仍然需要关闭我们的套接字并释放资源。在更加复杂的会话中,我们通常在调用closesocket()之前调用shutdown()来确定缓冲区已经被刷新,否则可能会有部分数据丢失。

closesocket(conn);

释放WinSock

我们调用WSACleanup()来结束WinSock的使用。

WSACleanup();

感谢您的阅读。


深入理解Winsock与TCP/IP在Windows下的网络通信 Windows网络编程接口,即Winsock,是Windows操作系统下用于网络通信的一套API。从其诞生至今,Winsock已经历多个版本的迭代,其中Winsock 2.0扩展了大量网络编程功能,以支持更复杂的应用程序需求。Winsock支持多种协议,尤其是广泛使用的TCP和UDP协议,使得开发者可以在Windows平台上创建客户端和服务器端的网络应用。客户端/服务器模型(Client/Server model)是一种分布式应用架构,其核心思想是将任务和服务分布在服务器端和客户端上。 阅读详情

相关推荐

R语言:基于Spatstat包的单变量和双变量平面Ripley‘s K函数分析

因为网上查找得到的R语言K函数分析的资料很少,Spatstat包的介绍也很少,所以抛砖引玉。本文简单介绍了使用R语言spatstat包的Kest,Kcross(Lcross)和Kinhom方法进行了单变量和双变量平面Ripley's K函数分析的方法及代码,希望有所帮助。

hsdcmax的博客 1万+

Winsock状态说明及错误代码

Winsock状态参数说明: 常数                               值    描述  sckClosed                       0    缺省值,关闭。  SckOpen                         1    打开。  SckListening                    2    侦听  s

Zr‘s code world 5314

树莓派4B学习笔记(5)—— 来个GPIO操作吧

一. GPIO库介绍 对于树莓派,现在有wiringPi,BCM2835,python三种库可以使用。 python 开发语言:python 简单介绍:树莓派官方资料中推荐且容易上手,毫无疑问的说python非常适合树莓派,树莓派也非常适合python。 wiring PI 开发语言:C、C++ 简单介绍:功能很强大,适合那些具有C语言基础,在接触树莓派之前已经接触过单片机或者嵌入式开发的人群。wiring Pi的API函数和arduino非常相似,且作者也给出了很多示例代码,这也使得它广受欢迎。

weixin_44415639的博客 8753

winsock实现TCP通信

对于多字节数据在内存中有两种存储方式: Little-endian:低字节在前,高字节在后; Big-endian:高字节在前,低字节在后 网络协议在处理多字节整数时,采用的是高端字节序,在编程时一定要考虑主机字节顺序与网络字节顺序的相互转换。 1      WinSock基本 1.1     加载/卸载WinSock库 如果装载Winsock1,那么必须include&lt;Winsoc...

liudongdong_jlu 3339

Playwright自动化测试实战:攻克日历时间控件三大策略与Java实现

在Web自动化测试领域,元素定位与交互模拟是核心技术基础,其原理在于通过程序精确识别并操作页面中的DOM元素,以模拟真实用户行为。这项技术的核心价值在于提升测试效率、确保交互逻辑的覆盖度与可靠性,广泛应用于电商、金融、OA等系统的功能验证。日历时间控件作为典型的复杂交互组件,常涉及动态弹出层、多级导航与状态同步,是自动化测试中的常见难点。本文聚焦于使用Playwright工具,针对此类控件深入剖析了三种核心解决策略:从最高效的直接赋值、到全面模拟用户交互的主流方法,再到利用组件特性的混合定位方案,并结合Ja

weixin_28835551的博客 311

EtherCAT主站IGH-- 49 -- 搭建xenomai系统及自己的IGH主站

以上就是搭建xenomai系统及自己的IGH主站的内容。有不明白的地方欢迎留言;有建议欢迎留言,我后面编写文档好改进。创作不容,如果文档对您有帮助,记得给个赞。

常驻客栈的博客--嵌入式EtherCAT 3158

winsock编程宝典

相信各位读者现在对於 Winsock 的定义、系统环境,以及一些 Winsock Stack 及 Winsock 应用程式,都有基本的认识了。接下来笔者希望能分几期为各位读者介绍一下简单的 Winsock 网路应用程式设计。 我们将以 Winsock 1.1 规格所定义的 46 个应用程式介面(API)为基础,逐 步来建立一对 TCP socket 主从架构(Client / Server)的程式

wewaa的专栏 2041

第八章 Vite4+Vue3+Vtkjs 完整demo演示

vtk.js是一个基于WebGL的开源3D可视化库,它可以在Web浏览器中呈现高质量的3D图形。vtk.js提供了一个易于使用的API,可以用于创建各种类型的3D可视化,包括科学、医学、工程和地球科学等领域。vtk.js支持多种数据格式,包括VTK、DICOM、STL等,可以轻松地将数据导入到可视化中。此外,vtk.js还支持交互式可视化,用户可以通过鼠标和键盘进行交互,探索和分析数据。采用的vite4+pinia搭建的Vue3项目。

Wait.End的博客 2234

Windows下的网络编程Winsock

相比于基础,网络编程就要复杂一些,但其实也有固定格式,记住即可。

森明帮大于黑虎帮的博客 6914

4、教育数据挖掘:公共数据集与研究进展

本文综述了教育数据挖掘(EDM)领域的研究进展与公共数据集应用情况。从2013年至2020年,EDM在电子学习系统、大规模开放在线课程(MOOC)等方面快速发展,涵盖了多种研究任务、工具与方法。文章梳理了UCI、Mendeley、DataShop等平台的公开数据集,分析了其特点与局限性,并介绍了KDD Cup、Kaggle等竞赛中的教育数据集及其评价指标。同时,探讨了多模态、心理行为等特色数据集的应用场景。最后指出当前EDM面临的主要挑战是缺乏系统性数据集综述、数据预处理复杂及可重复性不足,呼吁加强数据共享

rgv2345678的博客 171

在Android Jetpack Compose中实现夜间模式

Android基于Compose的深色主题实现

虎哥LoveDroid 1235

Winsock程序设计入门(2)

http://7622.com/list/50183.htm作者:Nishant S原文链接:http://www.codeproject.com/internet/winsockintro02.asp下载工程二、简单的TCP客户端介绍本文是《Winsock程序设计入门(1) - 简单的TCP服务器》一文的结局,如果你还没有读过第1部分的话,我还是建议你首先读一下。在本文中,我将示范给你如何编写一

zgbsoap的专栏 931

构建高效的LLM应用测试框架

《构建高效的LLM应用测试框架》 关键词:LLM,测试框架,应用测试,效率优化,测试原理 摘要:本文将深入探讨构建高效LLM应用测试框架的必要性、方法与步骤,旨在为开发者提供一套系统化、可操作的测试解决方案,从而提升LLM

AI天才研究院 1047

Winsock程序设计入门(1)

导读:   作者:Nishant S   原文链接:http://www.codeproject.com/internet/winsockintro01.asp   一、简单的TCP服务器   介绍   WinSock API是一套供Microsoft Windows操作系统使用的套接字程序库,它最初基于Berkeley套接字,但是其中加入了一些Microsoft的特殊改动。在这篇文章中,

yingfox的专栏 679

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

上一篇: WinSock学习笔记
下一篇: unix下编写socket程序的一般步骤
manplus
博客等级 码龄22年 6粉丝 160原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值