VC++ TCP网络控制台程序

在Windows7系统下,采用工具为VC++,Win32控制台应用程序,编写一个基于TCP的Client/Server网络程序。

1、服务器端代码

#include <WinSock2.h>
#include <stdio.h>

#define SERVERPORT 6000 //服务端口号

int main(int argc, char *argv[])
{
    //加载套接字库
    WORD wVersionRequested;//用于保存WinSock库的版本号
    WSADATA wsaData;
    int err;

    printf("This is a Server side application!\n");

    wVersionRequested = MAKEWORD(2,2);

    err = WSAStartup( wVersionRequested, &wsaData);
    if (err != 0)
    {
        printf("WSAStartup() called failed!\n");
        return -1;
    }
    else
    {
        printf("WSAStartup() called successful!\n");
    }

    if (LOBYTE(wsaData.wVersion) != 2 ||
          HIBYTE(wsaData.wVersion) != 2)
    {
        //若不是所请求的版本号2.2,则终止WinSock库的使用
        WSACleanup();
        return -1;
    }

    //创建用于监听的套接字
    SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
    if(sockServer == INVALID_SOCKET)
    {
        printf("socket() called failed! ,error code is: %d", WSAGetLastError());
        return -1;
    }
    else
    {
        printf("socket() called successful!\n");
    }

    //填充服务器端套接字结构
    SOCKADDR_IN addrServer;
    addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//将主机字节顺序转换成TCP/IP网络字节顺序
    addrServer.sin_family = AF_INET;
    addrServer.sin_port = htons(SERVERPORT);

    //将套接字绑定到一个本地地址和端口上
    err = bind(sockServer, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
    if (err == SOCKET_ERROR)
    {
        printf("bind() called failed! The error code is: %d\n", WSAGetLastError());
        return -1;
    }
    else
    {
        printf("bind() called successful\n");
    }
    //将套接字设置为监听模式,准备接收客户请求
    err = listen(sockServer, 5);
    if (err == SOCKET_ERROR)
    {
        printf("listen() called failed! The error code is: %d\n", WSAGetLastError());
        return -1;
    }
    else
    {
        printf("listen() called successful!\n");
    }

    SOCKADDR_IN addrClient; //保存发送请求连接的客户端的套接字信息
    int len = sizeof(SOCKADDR);

    while(1)
    {
        //等待客户请求到来
        SOCKET sockConn = accept(sockServer, (SOCKADDR*)&addrClient, &len);
        if (sockConn == INVALID_SOCKET)
        {
            printf("accept() called falied! The error code is: %d\n", WSAGetLastError());
        }
        else
        {
            printf("The Server receive a new client connection!\n");
        }

        char sendBuf[100];
        sprintf_s(sendBuf, 100, "Welcome %s",inet_ntoa(addrClient.sin_addr));

        //发送数据
        send(sockConn, sendBuf, strlen(sendBuf)+1 , 0);
        char recvBuf[100];
        //接收数据
        recv(sockConn, recvBuf, 100, 0);
        //打印接收到的数据
        printf("receive data from client side [%s,%d] is: %s\n", inet_ntoa(addrClient.sin_addr), addrClient.sin_port,
                              recvBuf);
        closesocket(sockConn);  //关闭连接套接字
    }

    return 0;
}
image.gif

2、客户端代码

#include <WinSock2.h>
#include <stdio.h>

#define SERVERPORT 6000 //服务端口号

#pragma comment(lib, "WS2_32.lib");

int main(int argc, char *argv[])
{
    //加载套接字库
    WORD wVersionRequested;
    WSAData wsaData;
    int err;

    printf("This is a Client side application!\n");

    wVersionRequested = MAKEWORD( 2, 2 );

    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0 )
    {
        /* Tell the user that we could not find a usable */
        /* WinSock DLL.                                  */
        printf("WSAStartup() called failed!\n");
        return -1;
    }
    else
    {
        printf("WSAStartup() called successful!\n");
    }

    if ( LOBYTE( wsaData.wVersion ) != 2 ||
        HIBYTE( wsaData.wVersion ) != 2 ) {
            /* Tell the user that we could not find a usable */
            /* WinSock DLL.                                  */
            WSACleanup( );
            return -1; 
    }

    /* The WinSock DLL is acceptable. Proceed. */

    //创建套接字
    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
    if(sockClient == INVALID_SOCKET)
    {
        printf("socket() called failed! ,error code is: %d", WSAGetLastError());
        return -1;
    }
    else
    {
        printf("socket() called successful!\n");
    }

    //需要连接的服务端套接字结构信息
    SOCKADDR_IN addrServer;
    addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//设定服务器的IP地址
    addrServer.sin_family = AF_INET;
    addrServer.sin_port = htons(SERVERPORT);//设定服务器的端口号(使用网络字节序)

    //向服务器发出连接请求
    err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
    if (err == SOCKET_ERROR)
    {
        printf("connect() called failed! The error code is: %d\n", WSAGetLastError());
        return -1;
    }
    else
    {
        printf("connect() called successful\n");
    }

    //接收数据
    char recvBuf[100]={0};
    recv(sockClient, recvBuf, 100, 0);
    printf("receive data from server side is: %s\n", recvBuf);

    //发送数据
    send(sockClient, "This is a client side!\n", strlen("This is a client side!\n")+1, 0);

    //关闭套接字
    closesocket(sockClient);

    //终止套接字库的使用
    WSACleanup();

    return 0;
}

image.gif

另外,需要注意的是需要在服务器和客户端都需要链接WinSock静态链接库Ws2_32.lib,有两种添加方法

方法一:在工程配置属性中添加

假如创建一个名为TCPClient的Win32控制台应用程序

在VS2017中添加静态链接库WS2_32.lib的方法如下:

(1)切换到TCPServer的【Solution Explorer】,选择菜单【Project】->【TCPClient Properties】

(2)在TCPClient Properties Pages对话框中,依次选择【Configuration Properties】->【Linker】->【Input】,在右侧的【Addtional Dependencies】中添加Ws2_32.lib库。

如下如所示:

image
image.gif

image
image.gif

服务器TCPServer也需要链接Ws2_32.lib库,方法和客户端TCPClient一样。

程序结果运行如下:

先启动服务器端程序TCPServer,结果如下:

[图片上传中...(image-434fe9-1601013270130-7)]

[图片上传中...(image-ee4558-1601013270129-2)] ​

再启动客户端TCPClient,客户端结果如下:

[图片上传中...(image-c6f83d-1601013270130-6)]

[图片上传中...(image-c0f11d-1601013270129-1)] ​

服务器端TCPServer结果如下:

image

[图片上传中...(image-44e9e1-1601013270129-0)] ​

方法二:在代码中添加

#pragma comment(lib, "WS2_32.lib");

参考资料:

1、《VC++深入详解》 第14章网络编程 ,孙鑫主编

2、MSDN帮助文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342