windows socket编程

#ifndef BASIC_MYLOCK_H

#define BASIC_MYLOCK_H

 

#ifdef _MSC_VER

#include <WinSock2.h> // 在每个windows.h 的include 前加 防止AF_IPX 重定义

#include "Windows.h"

//系统用的线程互斥锁。

namespace ITapManager

{

//线程同步类。是对Win32临界区对象的封装。

class CMyCriticalSection

{

public:

//CCriticalSection类的构造函数,初始化临界区,析构函数删除临界区。

CMyCriticalSection()        { ::InitializeCriticalSection(&m_crit); }

~CMyCriticalSection() { ::DeleteCriticalSection(&m_crit); }

//进人临界区

void Enter() { ::EnterCriticalSection(&m_crit); }

//离开临界区

void Leave() { ::LeaveCriticalSection(&m_crit); }

 

private:

//内部线程互斥对象

CRITICAL_SECTION m_crit;

};

typedef CMyCriticalSection CMylock;

 

 

//临界区锁类。构造函数加锁,析构函数解锁。

class CMyGuard

{

public:

CMyGuard(CMylock &crit) : m_crit(crit) { m_crit.Enter(); }

~CMyGuard() { m_crit.Leave(); }

private:

//内部正真的线程互斥对象的引用。

CMylock & m_crit;

};

}

#endif // _MSC_VER

#ifdef __GNUC__

 

#include <pthread.h>

namespace ITapManager

{

class CMyCriticalSection

{

public:

//CCriticalSection类的构造函数,初始化临界区,析构函数删除临界区。

CMyCriticalSection()

{

::pthread_mutex_init( &m_mutex, NULL);        //普通锁

}        

 

~CMyCriticalSection()

{

::pthread_mutex_destroy( &m_mutex);        

}

 

//进人临界区

void Enter() const

{

::pthread_mutex_lock( &m_mutex);        

}

 

//离开临界区

void Leave()

{

::pthread_mutex_unlock( &m_mutex);        

}

 

private:

//内部线程互斥对象

mutable pthread_mutex_t m_mutex;        

};

 

typedef CMyCriticalSection CMylock;

 

 

//临界区锁类。构造函数加锁,析构函数解锁。

class CMyGuard

{

public:

CMyGuard(CMylock &crit) : m_crit(crit) { m_crit.Enter(); }

~CMyGuard() { m_crit.Leave(); }

private:

//内部正真的线程互斥对象的引用。

CMylock & m_crit;

 

};

}

#endif // __GNUC__

       

#endif // BASIC_MYLOCK_H

 

 

 

 

 

//=====================MyCriticalSection.h===========================

#ifndef _My_CRITICAL_SECTION_H

#define _My_CRITICAL_SECTION_H

 

#include <windows.h>

//对临界区同样进行封装

class CMyCriticalSection

{

public:

    CMyCriticalSection()

    {

        InitializeCriticalSection(&m_cSection);

    }

 

    void Lock()

    {

        EnterCriticalSection(&m_cSection);

    }

 

    void UnLock()

    {

        LeaveCriticalSection(&m_cSection);

    }

 

 

    //利用析构函数删除临界区对象

    virtual ~CMyCriticalSection()

    {

        DeleteCriticalSection(&m_cSection);

    }

private:

    CRITICAL_SECTION                        m_cSection;

};

 

class CCriticalSectionAutoLock

{

public:

    //利用构造函数上锁,即进去临界区

    CCriticalSectionAutoLock(CMyCriticalSection *mySection)

    :pCMySection(mySection)

    {

        pCMySection->Lock();

    }

 

    //利用析构函数解锁,即离开临界区

    virtual ~CCriticalSectionAutoLock()

    {

        pCMySection->UnLock();

    }

private:

    CMyCriticalSection                      *pCMySection;

};

 

#endif

---------------------

作者:蓝色枫叶

来源:CSDN

原文:https://blog.csdn.net/olansefengye1/article/details/53262917

版权声明:本文为博主原创文章,转载请附上博文链接!

https://blog.csdn.net/YF_Li123/article/details/72863927

服务器端代码 server.cpp:

[cpp] 

view plain 

copy

客户端代码 client.cpp:

[cpp] 

view plain 

copy

 

将 server.cpp 和 client.cpp 分别编译为 server.exe 和 client.exe,先运行 server.exe,再运行 client.exe,输出结果为:

Message form server: Hello World!

 

Windows 下的 socket 程序和 Linux 思路相同,但细节有所差别:

1) Windows 下的 socket 程序依赖 Winsock.dll 或 ws2_32.dll,必须提前加载。DLL 有两种加载方式,请查看:动态链接库DLL的加载

 

2) Linux 使用“文件描述符”的概念,而 Windows 使用“文件句柄”的概念;Linux 不区分 socket 文件和普通文件,而 Windows 区分;Linux 下 socket() 函数的返回值为 int 类型,而 Windows 下为 SOCKET 类型,也就是句柄。

 

3) Linux 下使用 read() / write() 函数读写,而 Windows 下使用 recv() / send() 函数发送和接收。

 

4) 关闭 socket 时,Linux 使用 close() 函数,而 Windows 使用 closesocket() 函数。

 

WinSock(Windows Socket)编程依赖于系统提供的动态链接库(DLL),有两个版本:

几乎所有的 Windows 操作系统都已经支持 ws2_32.dll,包括个人操作系统 Windows 95 OSR2、Windows 98、Windows Me、Windows 2000、XP、Vista、Win7、Win8、Win10 以及服务器操作系统 Windows NT 4.0 SP4、Windows Server 2003、Windows Server 2008 等,所以你可以毫不犹豫地使用最新的 ws2_32.dll。

 

使用DLL之前必须把DLL加载到当前程序,你可以在编译时加载,也可以在程序运行时加载,《C语言高级教程》中讲到了这两种加载方式,请猛击:动态链接库DLL的加载:隐式加载(载入时加载)和显式加载(运行时加载)

 

这里使用#pragma命令,在编译时加载:

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

WSAStartup() 函数

使用DLL之前,还需要调用 WSAStartup() 函数进行初始化,以指明 WinSock 规范的版本,它的原型为:

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

wVersionRequested 为 WinSock 规范的版本号,低字节为主版本号,高字节为副版本号(修正版本号);lpWSAData 为指向 WSAData 结构体的指针。

关于 WinSock 规范

WinSock 规范的最新版本号为 2.2,较早的有 2.1、2.0、1.1、1.0,ws2_32.dll 支持所有的规范,而 wsock32.dll 仅支持 1.0 和 1.1。

 

wsock32.dll 已经能够很好的支持 TCP/IP 通信程序的开发,ws2_32.dll 主要增加了对其他协议的支持,不过建议使用最新的 2.2 版本。

 

wVersionRequested 参数用来指明我们希望使用的版本号,它的类型为 WORD,等价于 unsigned short,是一个整数,所以需要用 MAKEWORD() 宏函数对版本号进行转换。例如:

MAKEWORD(1, 2);  //主版本号为1,副版本号为2,返回 0x0201
MAKEWORD(2, 2);  //主版本号为2,副版本号为2,返回 0x0202

关于 WSAData 结构体

WSAStartup() 函数执行成功后,会将与 ws2_32.dll 有关的信息写入 WSAData 结构体变量。WSAData 的定义如下:

 

最后3个成员已弃之不用,szDescription 和 szSystemStatus 包含的信息基本没有实用价值,读者只需关注前两个成员即可。请看下面的代码:

 

运行结果:

wVersion: 2.2

wHighVersion: 2.2

szDescription: WinSock 2.0

szSystemStatus: Running

 

ws2_32.dll 支持的最高版本为 2.2,建议使用的版本也是 2.2。

 

综上所述:WinSock 编程的第一步就是加载 ws2_32.dll,然后调用 WSAStartup() 函数进行初始化,并指明要使用的版本号。

 

转载自:http://blog.csdn.net/ctrl_qun/article/details/52454232

 

来自 <https://blog.csdn.net/YF_Li123/article/details/72863927>

  • }
  • return 0;
  • WSAStartup( MAKEWORD(2, 2), &wsaData);
  • printf("wVersion: %d.%d\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
  • printf("wHighVersion: %d.%d\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
  • printf("szDescription: %s\n", wsaData.szDescription);
  • printf("szSystemStatus: %s\n", wsaData.szSystemStatus);
  • WSADATA wsaData;
  • int main(){
  • #include <stdio.h>
  • #include <winsock2.h>
  • #pragma comment (lib, "ws2_32.lib")
  • } WSADATA, *LPWSADATA;
  • char szSystemStatus[WSASYS_STATUS_LEN+1];
  • unsigned short iMaxSockets; //2.0以后不再使用
  • unsigned short iMaxUdpDg; //2.0以后不再使用
  • char FAR *lpVendorInfo; //2.0以后不再使用
  • //一个以 null 结尾的字符串,用来说明 ws2_32.dll 的状态以及配置信息
  • char szDescription[WSADESCRIPTION_LEN+1];
  • //一个以 null 结尾的字符串,用来说明 ws2_32.dll 的实现以及厂商信息
  • WORD wVersion; //ws2_32.dll 建议我们使用的版本号
  • WORD wHighVersion; //ws2_32.dll 支持的最高版本号
  • typedef struct WSAData {
  • 较早的DLL是 wsock32.dll,大小为 28KB,对应的头文件为 winsock1.h;
  • 最新的DLL是 ws2_32.dll,大小为 69KB,对应的头文件为 winsock2.h。
  •     //初始化DLL  
  •     WSADATA wsaData;  
  •     WSAStartup(MAKEWORD(2, 2), &wsaData);  
  •   
  •     //创建套接字  
  •     SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
  •   
  •     //向服务器发起请求  
  •     sockaddr_in sockAddr;  
  •     memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充  
  •     sockAddr.sin_family = PF_INET;  
  •     sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");  
  •     sockAddr.sin_port = htons(1234);  
  •     connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));  
  •   
  •     //接收服务器传回的数据  
  •     char szBuffer[MAXBYTE] = {0};  
  •     recv(sock, szBuffer, MAXBYTE, NULL);  
  •   
  •     //输出接收到的数据  
  •     printf("Message form server: %s\n", szBuffer);  
  •   
  •     //关闭套接字  
  •     closesocket(sock);  
  •   
  •     //终止使用 DLL  
  •     WSACleanup();  
  •   
  •     system("pause");  
  •     return 0;  
  • }  
  • int main(){  
  •   
  • #include <stdio.h>  
  • #include <stdlib.h>  
  • #include <WinSock2.h>  
  • #pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll  
  •     //初始化 DLL  
  •     WSADATA wsaData;  
  •     WSAStartup( MAKEWORD(2, 2), &wsaData);  
  •   
  •     //创建套接字  
  •     SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
  •   
  •     //绑定套接字  
  •     sockaddr_in sockAddr;  
  •     memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充  
  •     sockAddr.sin_family = PF_INET;  //使用IPv4地址  
  •     sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");  //具体的IP地址  
  •     sockAddr.sin_port = htons(1234);  //端口  
  •     bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));  
  •   
  •     //进入监听状态  
  •     listen(servSock, 20);  
  •   
  •     //接收客户端请求  
  •     SOCKADDR clntAddr;  
  •     int nSize = sizeof(SOCKADDR);  
  •     SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);  
  •   
  •     //向客户端发送数据  
  •     char *str = "Hello World!";  
  •     send(clntSock, str, strlen(str)+sizeof(char), NULL);  
  •   
  •     //关闭套接字  
  •     closesocket(clntSock);  
  •     closesocket(servSock);  
  •   
  •     //终止 DLL 的使用  
  •     WSACleanup();  
  •   
  •     return 0;  
  • }  
  • int main(){  
  •   
  • #include <stdio.h>  
  • #include <winsock2.h>  
  • #pragma comment (lib, "ws2_32.lib")  //加载 ws2_32.dll  

volatile 影响编译器编译的结果,指出volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。 

例如: 

volatile int i=10; 

int j = i; 

... 

int k = i; 

volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。 

优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。

/**********************

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 

 

来自 <https://blog.csdn.net/Yqq__00/article/details/25142093>

#pragma comment

 

来自 <http://c.biancheng.net/cpp/html/2754.html>

也可以在编译时候再调试选项中加入库

 WSASocket()

  简述:创建一个与指定传送服务提供者捆绑的套接口,可选地创建和/或加入一个套接口组。

  #include <winsock2.h>

  SOCKET WSAAPI WSASocket ( int af, int type, int

  protocol, LPPROTOCOL_INFO lpProtocolInfo, Group g,

  int iFlags);

  af:地址族描述。目前仅支持PF_INET格式,亦即ARPA Internet地址格式。

  type:新套接口的类型描述。

  protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。

  lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。

  g:套接口组的描述字。

  iFlags:套接口属性描述。

  返回值:

  若无错误发生,WSASocket()返回新套接口的描述字。否则的话,返回 INVALID_SOCKET,应用程序可定调用WSAGetLastError()来获取相应的错误代码。

  错误代码:

  WSANOTINITIALISED                在调用本API之前应成功调用WSAStartup()。

  WSAENETDOWN                 网络子系统失效。

  WSAEAFNOSUPPORT                不支持指定的地址族。

  WSAEINPROGRESS                一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数

  WSAEMFILE                                无可用的套接口描述字。

  WSAENOBUFS                        无可用的缓冲区空间。套接口无法创建。

  WSAEPROTONOSUPPORT        不支持指定的协议。

  WSAEPROTOTYPE                指定的协议对于本套接口类型错误。

  WSAESOCKTNOSUPPORT        本地址族不支持指定的套接口类型。

  WSAEINVAL                                g参数非法。

---------------------

作者:wiSCADA

来源:CSDN

原文:https://blog.csdn.net/wiscada/article/details/3051722

版权声明:本文为博主原创文章,转载请附上博文链接!

 bool tcpsocket()

    {

#if defined WIN32 || defined WIN64

        return socket(SOCK_STREAM, IPPROTO_TCP, WSA_FLAG_OVERLAPPED);

#endif

 

#ifdef linux

return socket(SOCK_STREAM, IPPROTO_TCP, 0);

#endif

    }

 

 

    bool socket(int type, int protocol, DWORD dwFlags)

    {

#if defined WIN32 || defined WIN64

// 重叠 I/O

m_Sock = ::WSASocket(AF_INET, type, protocol, 0, 0, dwFlags);

//m_Sock = ::WSASocket(AF_INET, 1,  IPPROTO_TCP, 0, 0, 0);

#endif

 

#ifdef linux

// I/O 复用

m_Sock = ::socket(AF_INET, type, protocol);

#endif

 

        return (INVALID_SOCKET != m_Sock);

    }

ioctlsocket()

简述:

控制套接口的模式。

#include <winsock.h>

int PASCAL FAR ioctlsocket( SOCKET s, long cmd, u_long FAR* argp);

s:一个标识套接口的描述字。

cmd:对套接口s的操作命令。

argp:指向cmd命令所带参数的指针。

注释:

本函数可用于任一状态的任一套接口。它用于获取与套接口相关的操作参数,而与具体协议或通讯子系统无关。支持下列命令:

FIONBIO:允许或禁止套接口s的非阻塞模式。argp指向一个无符号长整型。如允许非阻塞模式则非零,如禁止非阻塞模式则为零。当创建一个套接口时,它就处于阻塞模式(也就是说非阻塞模式被禁止)。这与BSD套接口是一致的。WSAAsynSelect()函数将套接口自动设置为非阻塞模式。如果已对一个套接口进行了WSAAsynSelect() 操作,则任何用ioctlsocket()来把套接口重新设置成阻塞模式的试图将以WSAEINVAL失败。为了把套接口重新设置成阻塞模式,应用程序必须首先用WSAAsynSelect()调用(IEvent参数置为0)来禁至WSAAsynSelect()。

FIONREAD:确定套接口s自动读入的数据量。argp指向一个无符号长整型,其中存有ioctlsocket()的返回值。如果s是SOCKET_STREAM类型,则FIONREAD返回在一次recv()中所接收的所有数据量。这通常与套接口中排队的数据总量相同。如果S是SOCK_DGRAM 型,则FIONREAD返回套接口上排队的第一个数据报大小。

SIOCATMARK:确实是否所有的带外数据都已被读入。这个命令仅适用于SOCK_STREAM类型的套接口,且该套接口已被设置为可以在线接收带外数据(SO_OOBINLINE)。如无带外数据等待读入,则该操作返回TRUE真。否则的话返回FALSE假,下一个recv()或recvfrom()操作将检索“标记”前一些或所有数据。应用程序可用SIOCATMARK操作来确定是否有数据剩下。如果在“紧急”(带外)数据前有常规数据,则按序接收这些数据(请注意,recv()和recvfrom()操作不会在一次调用中混淆常规数据与带外数据)。argp指向一个BOOL型数,ioctlsocket()在其中存入返回值。

兼容性:

本函数为Berkeley套接口函数ioctl()的一个子集。其中没有与FIOASYNC等价的命令,SIOCATMARK是套接口层次支持的唯一命令。

返回值:

成功后,ioctlsocket()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

错误代码:

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。

WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。

WSAEINVAL:cmd为非法命令,或者argp所指参数不适用于该cmd命令,或者该命令

不适用于此种类型的套接口。

WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。

WSAENOTSOCK:描述字不是一个套接口。

参见:

socket(), setsockopt(), getsockopt(), WSAAsyncSelect().

 

来自 <https://blog.csdn.net/andylin02/article/details/3184588>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值