Windows 网络编程基于TCP协议的Socket通信

来源:互联网 发布:数学算法 编辑:程序博客网 时间:2024/05/19 12:38
Socket套接字,是TCP/IP网络环境下应用程序与底层通信驱动程序之间运行开发接口,可以将应用程序与具体的TCP/IP隔离开来,使得应用程序不需要了解TCP/IP的具体细节,就能够实现数据传输。
Socket编程的层次结构

根据底层协议不同,Socket开发接口可以提供面向连接和无连接两种服务方式。
在面向连接的服务方式中,每次完整的数据传输都要经过建立连接、使用连接和关闭连接的过程。连接相当于一个传输管道,因此在数据传输过程中,分组数据包中不需要指定目的地址。TCP提供面向连接的虚电路。


服务器和客户机进程实现面向连接的Socket通信的过程

在Socket通信中,套接字分为3中类型:
1. 流式套接字
提供面向连接的、可靠地数据传输服务,可以无差错地发送数据。传输数据可以是双向的字节流,即应用程序采用全双工方式,通过套接字同时传输和接收数据。应用程序可以通过流传递有序的、不重复的数据,即数据包按发送顺序送达目的地址,且一个特定的数据包只能获取一次。适用于可靠且数据量大的传输。
2.数据报式套接字
提供面向无连接的数据传输服务。数据包被独立发送,数据可能丢失或重复。
3.原始套接字
公开的Socket编程接口,可以在IP层上对Socket进行编程,发送和接收IP层上的原始数据包。

服务端的示例代码:

// TCP Socket.cpp : 定义控制台应用程序的入口点。// TCPServer服务器程序#include "stdafx.h" //默认包含的头文件,用于实现头文件的预编译#include<WINSOCK2.H> //用于管理WIndows Sockets版本2函数的头文件#include<iostream> //用于管理输入输出流的头文件#pragma comment(lib,"WS2_32.lib")#define BUF_SIZE 128 //缓冲区大小#define PORT 9990int _tmain(int argc, _TCHAR* argv[]){    //声明变量    WSADATA wsd;  //wsadata变量,初始化Windows socket    SOCKET sServer; //服务器Socket,用于监听客户端的请求    SOCKET sClient; //客户端Socket,用于实现与客户端的通信    int retVal;  //调用各种Socket函数的返回值    int on; //设置setsocket参数时使用    char buf[BUF_SIZE];    //初始化Socket动态库    if (WSAStartup(MAKEWORD(2,2),&wsd)!=0)    {        printf("WSAStartup failed !\n");        return -1;    }    //创建用于监听的Socket    sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);    if (INVALID_SOCKET == sServer)    {        printf("Socket failed!\n");        WSACleanup();        return -1;    }    else        printf("Create Socket OK\n");    on = 1;    setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)); //允许地址重用    //设置服务器Socket地址    SOCKADDR_IN addrServ;    addrServ.sin_family = AF_INET; //地址家族    addrServ.sin_port = htons(9990); //端口    addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //地址,host_id转为net_id,类型u_long    //绑定Socket Server到本地地址    retVal = bind(sServer,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN));    if (SOCKET_ERROR == retVal)    {        printf("bind failed ! \n");        closesocket(sServer);        WSACleanup();        return -1;    }    printf("socket bind OK!\n");    //在Socket Server上进行监听    retVal = listen(sServer, 1);    if (SOCKET_ERROR == retVal)    {        printf("listen failed!/n");        closesocket(sServer);        WSACleanup();        return -1;    }    printf("socket listen OK!\n");    //接收来自客户端的请求    printf("TCP Server start....\n");    sockaddr_in addrClient;    int addrClientlen = sizeof(addrClient);    sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);    if (INVALID_SOCKET == sServer)    {        printf("accept failed! \n");        closesocket(sServer);        WSACleanup();        return -1;    }    printf("accept a connect request !\n");    //在服务器与客户端之间收发数据    while (true)    {        //循环接收数据,直到客户端发送“quit”后退出        ZeroMemory(buf, BUF_SIZE);        retVal = recv(sClient, buf, BUFSIZ, 0);        if (SOCKET_ERROR == retVal)        {            printf("recv failed! \n");                      closesocket(sClient);            WSACleanup();            return -1;        }        if (retVal == 0)  //0代表客户端断开连接        {            printf("socket close connection.\n");            closesocket(sClient);            return -1;        }        //获取系统当前时间        SYSTEMTIME st;        GetLocalTime(&st);        char sDataTime[30];        sprintf_s(sDataTime,"%4d-%2d-%2d %2d-%2d-%2d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);        printf("\nTime[%s]\n Recv from Client[%s:%d]:%s\n",sDataTime,inet_ntoa(addrClient.sin_addr),addrClient.sin_port,buf);        char msg[BUF_SIZE];        sprintf_s(msg, "%s", buf);  //输出到字符串msg中        for (int i = 0; i < sizeof(msg); i++)   //将接收到的数据转为大写            msg[i] = toupper(msg[i]);        retVal = send(sClient, msg, strlen(msg), 0);        if (SOCKET_ERROR == retVal)        {            printf("send failed !\n");            closesocket(sServer);            closesocket(sClient);            WSACleanup();            return -1;        }    }    //释放资源    closesocket(sServer);    closesocket(sClient);    WSACleanup();    //暂停,按任意键退出    system("pause");    return 0;}


客户端的示例代码:

// TcpSocketClient.cpp : 定义控制台应用程序的入口点。// TCP Client 客户端程序#include "stdafx.h"#include<WINSOCK2.H>#include<string>#include<iostream>#pragma comment(lib,"WS2_32.lib")#define BUF_SIZE 128#define PORT 9990int _tmain(int argc, _TCHAR* argv[]){    //声明变量    WSADATA wsd; //用于初始化windows socket    SOCKET sHost;  //与服务器进行通信的socket    SOCKADDR_IN servAddr; //服务器地址    char buf[BUF_SIZE]; //接收数据缓冲区    int retVal; //调用各种socket函数的返回值    //初始化Socket环境    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)    {        printf("WSAStartup failed !\n");        return 1;    }    //创建用于通信的Socket    sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (INVALID_SOCKET == sHost)    {        printf("socket faild !\n");        WSACleanup();        return -1;    }    //设置服务器的Socket地址    servAddr.sin_family = AF_INET;    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");    //servAddr.sin_addr.S_un.S_addr = inet_addr("172.18.147.35");    servAddr.sin_port = htons(PORT);    int sServerAddlen = sizeof(servAddr);    //连接到服务器    retVal = connect(sHost, (SOCKADDR*)&servAddr, sizeof(servAddr));    if (SOCKET_ERROR == retVal)    {        printf("connect failed!\n");        closesocket(sHost);        WSACleanup();        return -1;    }    printf("socket connect OK!\n");    //服务器和客户端收发数据    while (true)    {        printf("Please input a string to send: ");        std::string str;        std::getline(std::cin, str);        ZeroMemory(buf, BUF_SIZE);        strcpy_s(buf, str.c_str());        //注意recv和send是阻塞的,不能同时收发        retVal = send(sHost, buf, strlen(buf), 0);        if (SOCKET_ERROR == retVal)        {            printf("send failed!\n");            closesocket(sHost);                     return -1;        }        //服务器接收回传的数据        retVal = recv(sHost, buf, sizeof(buf), 0);        if (SOCKET_ERROR == retVal)        {            printf("receive failed!\n");            closesocket(sHost);            return -1;        }        printf("Recv From Server: %s\n", buf);              //释放资源        closesocket(sHost);        WSACleanup();        system("pause");        return 0;    }}

代码说明:
示例代码实现了服务端接收客户端发来的字符串,然后将所有字符串转为大写字母,再重新发回到客户端。
首先运行服务端程序,再运行客户端程序。

0 0
原创粉丝点击