Winsock编程_第1篇_TCP套接字编程

      最近受一位编程牛人的影响,自己决定从今天开始将Windows Sockets 网络编程的内容以日志的形式记录下来,其一是为自己保留一份笔记,其二是加深自己对winsock编程的理解,其三是和喜欢代码的朋友一起分享编程的乐趣,我不知道自己能不能一直坚持下去,但是我会尽自己最大的努力做到每周更新1-2篇,在此也希望更多的朋友为我提出建议,如果你也喜欢编程,在阅读代码的过程中有什么疑问,请与本人进行探讨。
        每次我会以一段程序代码的分析来阐述其中的知识点,因为阅读大量优秀代码可以快速提升自身的编程水平。

      首先介绍下计算机通信系统互联参考模型OSI (Open System Interconnection)

Winsock编程_第1篇_TCP套接字编程


这就是OSI模型,重最底部的物理层开始到最顶部的应用层结束,该模型的7层完整结构阐述了基本的网络概念。具体内容可查阅百度。

TCP/IP模型分为四层结构:

Winsock编程_第1篇_TCP套接字编程

应用层:相当于OSI模型的上面三层,包括各种应用程序和协议,协议有HTTP,FTP等等
传输层:包括TCP、UDP协议
网络层:IP、ARP、RARP、ICMP协议
数据链路层:相当于OSI模型的下面两层,通俗点说这一层就是网卡驱动和网卡物理设备。
sockets编程发生在应用层和传输层之间。
 接下来以一个简单的TCP通信程序作为示例:
编译器Visual Stdio 2012,实现代码C++。
 Server Code:

// Server.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "winsock2.h"
#define  BUF_SZIE     64
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
    WSADATA            wsad;            //WSADATA变量
    SOCKET            Server;        //服务器套接字
    SOCKET            Client;        //客户端套接字
    SOCKADDR_IN        addrServ;        //服务器地址
    char            buf[BUF_SZIE];        //接收数据缓冲区
    int                retVal;        //返回值

    //初始化套接字动态库
    if (WSAStartup(MAKEWORD(2,2),&wsad) != 0)
    {
        printf("初始化套接字动态库失败!\n");
        return 1;
    }
    
    //创建套接字
    Server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    
    if(INVALID_SOCKET == Server)
    {
        printf("创建套接字失败!\n");
        WSACleanup();//释放套接字资源;
        return  -1;
    }
    
    //服务器套接字地址 
    addrServ.sin_family = AF_INET;
    addrServ.sin_port = htons(2012);
    addrServ.sin_addr.s_addr = INADDR_ANY;        
    //绑定套接字
    retVal = bind(Server, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
    if(SOCKET_ERROR == retVal)
    {    
        printf("绑定套接字失败!\n");
        closesocket(Server);    //关闭套接字
        WSACleanup();            //释放套接字资源;
        return -1;
    }
    
    //开始监听 
    retVal = listen(Server, 1);
    if(SOCKET_ERROR == retVal)
    {
        printf("监听失败!\n");        
        closesocket(Server);    //关闭套接字
        WSACleanup();            //释放套接字资源;
        return -1;
    }
    
    //接受客户端请求
    sockaddr_in addrClient;
    int addrClientlen = sizeof(addrClient);
    Client = accept(Server,(sockaddr FAR*)&addrClient, &addrClientlen);
    if(INVALID_SOCKET == Client)
    {
        printf("接受客户端请求失败!\n");        
        closesocket(Server);    //关闭套接字
        WSACleanup();            //释放套接字资源;
        return -1;
    }
    
    //接收客户端数据
    ZeroMemory(buf, BUF_SZIE);
    retVal = recv(Client, buf, BUF_SZIE, 0);
    if (SOCKET_ERROR == retVal)
    {
        printf("接收客户端请求失败!\n");        
        closesocket(Server);    //关闭套接字
        closesocket(Client);    //关闭套接字        
        WSACleanup();            //释放套接字资源;
        return -1;
    }

    printf("%s\n", buf);    //输出来自Client的字符串    

    //退出
    closesocket(Server);    //关闭套接字
    closesocket(Client);    //关闭套接字
    WSACleanup();            //释放套接字资源;
    return 0;
}
Client Code:


// Client.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#define    BUF_SZIE    64
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{

    WSADATA            wsad;            //WSADATA变量
    SOCKET            sHost;            //服务器套接字
    SOCKADDR_IN        servAddr;        //服务器地址
    char            buf[BUF_SZIE];    //接收数据缓冲区
    int                retVal;            //返回值
    
    //初始化套接字动态库
    if (WSAStartup(MAKEWORD(2,2), &wsad) != 0)
    {
        printf("初始化套接字失败!\n");
        return -1;
    }
    
    //创建套接字
    sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    
    if(INVALID_SOCKET == sHost)
    {
        printf("创建套接字失败!\n");
        WSACleanup();//释放套接字资源
        return  -1;
    }

    //设置服务器地址
    servAddr.sin_family =AF_INET;
    servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servAddr.sin_port = htons((short)2012);
    int    nServAddlen  = sizeof(servAddr);

    //连接服务器
    retVal=connect(sHost,(LPSOCKADDR)&servAddr, sizeof(servAddr));    
    if(SOCKET_ERROR == retVal)
    {
        printf("连接服务器失败!\n");    
        closesocket(sHost);    //关闭套接字
        WSACleanup();        //释放套接字资源
        return -1;
    }
    
    //向服务器发送数据
    ZeroMemory(buf, BUF_SZIE);
    strcpy(buf, "2012年12月13日");
    retVal = send(sHost, buf, strlen(buf), 0);
    if (SOCKET_ERROR == retVal)
    {
        printf("发送数据失败!\n");
        closesocket(sHost);    //关闭套接字
        WSACleanup();        //释放套接字资源
        return -1;
    }
    
    //退出
    closesocket(sHost);    //关闭套接字
    WSACleanup();        //释放套接字资源
    return 0;
}
虽说该程序比较简单,但是麻雀虽小五脏俱全,程序代码旨在突出开发TCP应用程序的框架,其中Server 、Client调用Windows Sockets API的过程如下所示:


Winsock编程_第1篇_TCP套接字编程Winsock编程_第1篇_TCP套接字编程

程序运行结果:


Winsock编程_第1篇_TCP套接字编程


转载请注明出处,谢谢!


你可能感兴趣的:(TCP/IP,socket编程,winsocket)