Socket

原创 2005年04月23日 21:55:00
 

作者:Nishant S
原文链接:http://www.codeproject.com/internet/winsockintro01.asp

一、简单的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()返回的时候,进程就会被终止,主线程开启的线程也会被突然终止。

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:~$

Socket 发送接收图像

客户端代码: #include #include #include #pragma comment(lib,"ws2_32.lib") using namespace std; si...
  • u014080185
  • u014080185
  • 2017年05月04日 16:44
  • 627

Socket错误详解及处理方法

例如错误代码10061, 说明服务器已经找到,但连接被服务器拒绝,连接失败原因可能是: 端口号设置错误; 2.服务器没有处于监听状态 (即ServerSocket –>Active=true);3.数...
  • singular2611
  • singular2611
  • 2015年03月27日 12:46
  • 7533

socket函数返回值分析

服务端: 1 WSAStartup(版本,本机的最高版本) WSAStartup函数的第一个参数是加载WinSock库的版本,WSAStartup函数的第二个参数中设置使用的W...
  • liuyueyue0921
  • liuyueyue0921
  • 2015年08月21日 10:19
  • 6453

Loadrunner编写socket性能测试脚本简述

一、概述         Loadrunner拥有极为丰富的工具箱,供予我们制造出各种奇妙魔法的能力。其中就有此次要讨论的socket套接字操作。       二、socke...
  • louishu_hu
  • louishu_hu
  • 2016年08月09日 09:43
  • 5164

常见的socket出错总结

case ECONNREFUSED:  reason = REASON_NO_SUCH_PORT; break;      没有这个端口             case EAGAIN:       ...
  • epeaktop
  • epeaktop
  • 2015年09月24日 19:20
  • 8412

监听socket初始化

主要在俩块内容中用到socket的初始化部分,第一块是在ngx_http_core_srv函数中,在最后设置默认的监听套接口时有把监听socket添加进去,第二块是在ngx_http_block的最后...
  • wellwang1993
  • wellwang1993
  • 2016年04月18日 15:57
  • 725

socket()函数介绍

socket()函数介绍 socket函数介绍 函数原型 domain type protocol errno 示例
  • xc_tsao
  • xc_tsao
  • 2015年03月08日 10:46
  • 11669

Socket 通信原理机制

我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so...
  • Tom_and_Jerry_zhao
  • Tom_and_Jerry_zhao
  • 2015年11月25日 21:55
  • 4706

socket编程 -- 大端小端区别及转换

计算机数据存储有两种字节优先顺序:高位字节优先(称为大端模式)和低位字节优先(称为小端模式)。内存的低地址存储数据的低字节,高地址存储数据的高字节的方式叫小端模式。内存的高地址存储数据的低字节,低地址...
  • y396397735
  • y396397735
  • 2016年02月13日 23:40
  • 1554

socket系列之什么是socket

1、什么是socket Socket是应用层与TCP/IP协议族通信的中间抽象层,它是一组接口,应用层通过调用这些接口实现发送和接收数据。一般这种抽象层由操作系统提供或者由JVM自己实现。使用sock...
  • wangyangzhizhou
  • wangyangzhizhou
  • 2014年11月22日 23:53
  • 2145
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章: Socket
举报原因:
原因补充:

(最多只允许输入30个字)