您的位置:首页 > 运维架构

VC写的socket程序实现一个简单Echo服务器端和客户端程序

2010-12-21 11:54 801 查看
用一个简单的程序来学习VC Socket编程。

本程序实现一个echo服务,即回送服务,客户端向服务器端发送一段数据,服务器收到后,立即将该段数据回送给客户端。

 

在Visual Studio 2010开发环境中,新建一个project,选择Visual C++/Win32/Win32 Console Application,project name是echoServer,同样的方法,新建一个echoClient项目。

 

echoServer.cpp文件中的代码如下:

// echoServer.cpp : 这是一个控制台程序,使用socket编程方法,实现echo服务的服务器端

//本程序的socket是基于TCP的流式套接字

#include "stdafx.h"

#include <WinSock2.h>

//链接一个ws2_32.lib的库文件

#pragma comment (lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])

{

    if (argc<2){

        printf("请附带本程序要监听的端口参数。/n");

        return -1;

    }

    WORD wVersionRequested;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 1, 1 );

    //加载套接字库,创建套接字

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

        printf("创建socket失败。");

        return err;

    }

 

    if ( LOBYTE( wsaData.wVersion ) != 1 ||

        HIBYTE( wsaData.wVersion ) != 1 ) {

        WSACleanup();

        printf("创建socket失败。");

        return -1;

    }

    SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);

    //取本机的IP地址作为socket监听地址

    SOCKADDR_IN addrSrv;

    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

    addrSrv.sin_family=AF_INET;

   

    //用第一个命令行参数作为监听的端口

    int port=atoi(argv[1]);

    addrSrv.sin_port=htons(port);

 

    //绑定套接字到一个IP地址和一个端口上

    bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

    printf("本echo服务程序正在监听端口:%d/n",port);

    //将套接字设置为监听模式等待连接请求

    listen(sockSrv,5);

    SOCKADDR_IN addrClient;

    int len=sizeof(SOCKADDR);

    //以一个无限循环的方式,不停地接收客户端socket连接

    while(1)

    {

        //请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字

        SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);

        //接收缓冲区的大小是50个字符

        char recvBuf[50];

        recv(sockConn,recvBuf,50,0);

        //发送信息的缓冲区的大小也是50个字符

        char sendBuf[50];

        //准备要发送的信息,只是将接收到信息原样返回给客户端

        sprintf(sendBuf,"%s",recvBuf);

        send(sockConn,sendBuf,strlen(sendBuf)+1,0);

 

        printf("接收来自客户端%s的信息:%s/n",inet_ntoa(addrClient.sin_addr),recvBuf);

        //结束连接

        closesocket(sockConn);

    }

 

    return 0;

}

 

此程序存在一些不足:

1、如果第一个命令行参数不是一个有效的TCP端口数字时,程序会以0作为端口。

2、当端口已经正被占用时,程序不能正常工作,不停地有提示:"接收来自客户端204.204.204.204的信息:烫烫烫烫......"

3、没有采用多线程来处理客户端的socket连接(实际上这个简单的应用没有必要用到多线程,因为客户端对服务器的连接非常短暂)

 

echoClient.cpp文件中的代码如下:

// echoClient.cpp : 这是一个控制台程序,使用socket编程方法,实现echo服务的客户端

//本程序的socket是基于TCP的流式套接字

#include "stdafx.h"

#include <WinSock2.h>

//需要链接一个ws2_32.lib的库文件

#pragma comment (lib,"ws2_32.lib")

int _tmain(int argc, _TCHAR* argv[])

{

    if (argc<3){

        printf("请附带三个参数:服务器端程序监听的IP地址和端口,以及回显的信息。/n");

        return -1;

    }

    WORD wVersionRequested;

    WSADATA wsaData;

    int err;

 

    wVersionRequested = MAKEWORD( 1, 1 );

 

    err = WSAStartup( wVersionRequested, &wsaData );

    if ( err != 0 ) {

        printf("创建socket失败。");

        return err;

    }

 

    if ( LOBYTE( wsaData.wVersion ) != 1 ||

        HIBYTE( wsaData.wVersion ) != 1 ) {

        WSACleanup();

        printf("创建socket失败。");

        return -1;

    }

    SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);

 

    //用第一个命令行参数作为要连接服务器程序的IP地址

    SOCKADDR_IN addrSrv;

    char* ip=argv[1];

    addrSrv.sin_addr.S_un.S_addr=inet_addr(ip);

    addrSrv.sin_family=AF_INET;

    //用第二个命令行参数作为连接服务器端程序的端口

    int port=atoi(argv[2]);

    addrSrv.sin_port=htons(port);

    //向服务器发出连接请求

    connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));

    //第三个命令行参数是要发送给服务器端程序的信息

    char* msg=argv[3];

    send(sockClient,msg,strlen(msg)+1,0);

    //接收来自服务器端程序的信息

    char recvBuf[50];

    recv(sockClient,recvBuf,50,0);

    //输出回显

    printf("%s/n",recvBuf);

 

    //关闭socket连接

    closesocket(sockClient);

    WSACleanup();

    return 0;

}

此程序存在一些不足:

1、没有对命令行参数的有效性进行验证。

2、连接到服务器端失败时的错误提示是乱码。"烫烫烫烫.......
"

3、如果命令行参数中第三个参数是长于50个字符的信息会超出缓冲区的容量。

 

要编译这两个程序需要修改project的properties,将其中的Character Set由Use Unicode Character Set修改为Use Multi-byte Charactoer Set,否则会提示_TCHAR不能转换为const char*的错误,另外,取命令行参数argv中的字符串时,如果只能取到字符串的第一个字符,也是需要修改此属性。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐