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

用一个简单的程序来学习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
//链接一个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
//需要链接一个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中的字符串时,如果只能取到字符串的第一个字符,也是需要修改此属性。

 

你可能感兴趣的:(学习C/C++)