socket编程入门(函数)

Windows Socket 编程

   

一、 Windows sockets开发概述

网络开发可被理解为:基于互联网,利用网络开发技术,开发能运行在网络上的软件,如网络游戏、聊天软件等。

Windows sockets是一套在Microsoft Windows环境下的网络编程接口,它包含一组库函数,使开发人员可以利用Windows消息驱动机制进行网络应用程序开发

Windows sockets 主要有 Windows sockets 1.1(1.0)和Windows sockets 2.2(2.0) 两个版本。

版本

头文件

库文件

动态库

1.1

WINSOCK.h

wsock32.lib

WINSOCK.DLL

2.2

WINSOCK2.h

WS2_32.lib

WS2_32.dll

Socket1.1版本中用到的库函数主要有:

Accept(), bind(), closesocket(), connect(), getpeername(), getsockname(), htonl(), htons(), inet_addr(), inet_ntoa(), listen(), ntohl(), ntohs(), recv(), recvfrom(), select(), send(), sendto(), shutdown(), socket()等

Socket1.1版本中对Windows扩展的函数主要有:

WSAStartup(), WSACleanup(), WSAGetLastError(), WSAIsBlockint()等

Socket2.0版本中对Windows扩展的函数主要有:

WSAACCEPT(), WSACONNECT(), WSAHTONL(), WSAHTONS(), WSANTOHL(), WSANTOHS(), WSARECV(), WSARECVFROM(), WSASEND(), WSASENDTO(), WSASOCKET()等

   

   

二、TCP/IP 简介

& TCP/IP协议

TCP/IP协议是网络通信中最常用的协议

OSI标准

TCP/IP模型

协议

应用层

应用层

HTTP/FTP

表示层

  

  

会话层

  

  

传输层

传送层

TCP/UDP

网络层

网络层

IP/ARP(地址解析协议)

数据链路层

数据链路层

  

物理层

  

  

套接字:应用层到传送层的接口

& 端口:

0-1023:通用端口号

1024-49151:应用程序使用

49152-65535:动态、私有端口

   

   

   

三、WINDOWS SOCKETS 基础

(一)套接字

套接字:网络应用程序借口,应用层与传送层得接口

   

(二)TCP,UDP 连接过程

Tcp

  

Udp

Server

Client

  

Server

Client

创建套接字

创建套接字

  

创建套接字

创建套接字

绑定

  

  

绑定

发送数据

监听

连接

  

接受数据

  

接受连接

  

  

关闭

关闭

收发数据

收发数据

  

  

  

关闭

关闭

  

  

  

对应tcp、udp,至少有两种套接字可供编程使用,即流套接字和数据包套接字

在Windows sockets中有一个新的数据类型SOCKET表示套接字,声明如下:

Typedef unsigned int u_int;

Typedef u_int SOCKET;

即用一个特殊的整型变量表示套接字

(三)sockets中用到的函数

& 开始sockets编程

利用vc 开发sockets程序时,需首先导入库文件,导入库文件的方法:

1.头文件中添加代码:#pragma comment(lib,"wsock32.lib");或"WS2_32.lib"

2.菜单栏"project"—"project settings"对话框---"link"选项卡---"category"下拉框中选择"input"----"object/library modules"文本框中添加"wsock32.lib"(前面加空格)

推荐使用第一种方法,因第二种方法在每次打开工程时,都需从新执行添加步骤。

Socket2版本兼容socket1版本,但如果程序中用到socket2版本中的函数时,需导入socket2的库文件。

   

& WSAStartup()

功能:对Winsock服务的初始化。应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数。

声明:WSAStartup(

__in        WORD wVersionRequested,     //程序请求使用的Socket版本

__out    LPWSADATA lpWSAData)    //操作系统返回支持的Socket的版本

返回:成功时返回0

wVersionRequested:准备加载的动态库版本,高字节指定副版本,低字节指定主版本

LpWSAData:指针,WSADATA结构,返回被加载的动态库特征

用到的其他知识:

wVersionRequested对象可用MAKEWORD函数进行赋值e.g.MAKEWORD(2.0)

wsaData返回后,可用LOBYTE(wsaData),HIBYTE(wsaData)查看返回的主版本号与副版本号

例如:

WORD wVersionRequest MAKEWORD(2,2);

WSADATA wsaData;

int errCode=WSAStartup(wVersionRequest, &wsaData); //初始化

if(errCode != 0){......} //error

if(LOBYTE(wsaData)!=2 || HIBYTE(wsaData)!=2){……}; //主、副版本号

   

& socket()

功能:创建套接字,利用socket1.1版本中的socket()函数或socket2.2版本中的WSASocket()函数可实现此功能

声明:SOCKET socket(

__in        Int af,                        //协议的地址家族

__in        Int type,                        //协议的套接字类型

__in        Int protocol)                    //协议

af:地址家族,创建tcp或udp连接时,此参数为AF_INET(Address family地址家族)

type:套接字类型,可选项有:

SOCK_STREAM(流式套接字,tcp使用)

SOCK_DGRAM(数据报套接字,udp使用)

SOCK_RAM(原始套接字,直接处理ip协议)

protocol:对于SOCK_STREAM,该字段为IPPROTO_TCP或0(自动匹配)

    对于SOCK_DGRAM,该字段为IPPROTO_UDP或0(自动匹配)

返回:socket 类型,失败时返回INVALID_SOCKET

用到的其他知识:

Socket类型:

定义:typedef unsigned int u_int;

Typedef u_int SOCKET;

Socket对象也就是一个特殊的整数

取值范围:0到(INVALID_SOCKET - 1)

    创建时,若返回值为INVALID_SOCKET,则创建失败。

    #define INVALID_SOCKET (SOCKET)(~0)

例如:

SOCKET s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

If(INVALID_SOCKET == s) {……} //创建失败

   

& bind()

功能:套接字绑定到地址

声明:int bind(

__in        SOCKET s,                     //要绑定的套接字

__in        const struct sockaddr FAR* name , //绑定到的地址

__in        int namelen);                    //地址的长度

返回:失败时为SOCKET_ERROR;

例如:

Struct sockaddr_in servAddr;

   

servAddr.sin_family=AF_INET;

servAddr.sin_port=htons(4999);

servAddr.sin_addr.s_addr=htonl(INADDR_ANY);

//servAddr.sin_addr.s_addr=inaddr_any

//servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");

   

int errorCode=bind(s, (SOCKET*)&servAddr, sizeof(servAddr)):

if(SOCKET_ERROR==errorCode) {……} //error

   

   

& listen()启动监听

功能:将套接字设置为监听模式

声明:int listen(

__in        socket s,                    //要设置为监听的套接字

__in        int backlog);                //等待队列最大长度

返回:成功时返回0,失败时返回 SOCKET_ERROR

例如:

Int Val=listen(s, 5);

If(SOCKET_ERROR==Val) {……} //error

   

& accept()

功能:接受一个连接请求

声明:socket accept(

__in        socket s,                     //监听套接字

__out    struct sockaddr FAR* addr,    //地址

__out    int FAR* addrlen)            //地址长度

返回:代表客户端的socket ,失败时返回 INVALID_SOCKET;

例如:

SOCKET sAccept;

Sockaddr_in addrClient;

Int addrClientLen=sizeof(addrClient);

sAccept=accept(s,(SOCKADDR*)&addrClient,&addrClientLen);

if(INVALID_SOCKET==sAccept) {……} //error

   

& recv() 或 WSARecv()

功能:接收数据

声明:int recv(

__in        socket s,            //套接字

__in        char FAR* buf,     //缓冲区

__in        int len,             //缓冲区长度

__in        int flags)            //标志,0:无特殊行为

返回:成功时,返回接受的字节数,失败时,返回SOCKET_ERROR

例如:

Char buf[BUF_LEN];

Int readLen;

readLen=recv(sAccept,buf,BUF_LEN,0);

if(SOCKET_ERROR==readLen) {……} //error

   

& send() 或 WSASend()

功能:发送数据

声明:int send(

__in        socket s,                //套接字

__in        const char FAR* buf,    //缓冲区

__in        int len ,                //缓冲区长度

__in        int flags)                //标志,0:无特殊行为

返回:失败时,SOCKET_ERROR

例如:

Char buf[BUF_LEN];

Int writeLen;

writeLen= send (sAccept,buf,BUF_LEN,0);

if(SOCKET_ERROR==writeLen) {……} //error

   

& Closesocket()

功能:关闭套接字,释放资源

声明:int closesocket(

__in        s);            //要关闭的套接字

返回:WSAENOTSOCK错误

   

& Shutdown()

功能:关闭套接字连接

声明:int shutdown(

__in        socket s,        //套接字

__in        int how);        // SD_RECEIVE:不接受,SE_SEND:不发送,SD_BOTH:都不

返回:int

   

& connect()

功能:连接到服务器

声明:int connect(

__in        socket s,                            //套接字

__in        const struct sockaddr FAR* name ,        //服务器地址

__in        int namelen)                        //服务器地址长度

返回:失败时,返回SOCKET_ERROR

例如:

SOCKET sHost; //连接服务器的套接字

SOCKEADDR_IN addrServerAddr;//服务器地址

   

sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

addrServerAddr.sinfamily=AF_INET;

addrServerAddr.sin_port=htons(serverPort);

addrServerAddr.sin_addr.s_addr=htohl(serverIP);

   

int Val= connect (sHost, (LPSOCKADDR)&addrServerAddr, sizeof(addrServerAddr));

if(SOCKET_ERROR==Val) {……} //error

   

& sendto()

功能:发送数据

定义:int sendto(

SOCKET s,

const char FAR* buf,

int len,

int flags,

const struct sockaddr FAR* to,

int tolen);

   

& recvfrom()

功能:接受数据,返回发送数据主机的地址

声明:int recvfrom(

__in        SOCKET s,                //接受套接字

__in        char FAR* buf;                //接受缓冲区

__in        len,                        //接受缓冲区大小

__out    struct sockaddr FAR* from;    //返回发送主机地址

__out    int FAR* fromlen)            //地址长度

返回:成功时,返回接受数据的长度;失败时,返回SOCKET_ERROR

例如:

char buf[BUF_LEN];

SOCKADDR_IN addrClient;

Int nAddrClient=sizeof(addrClient);

recvfrom(s,buf,BUF_SIZE,0,(SOCKADDR*)&c addrClient,& nAddrClient)

   

& Socketaddr_in 结构

   

Struct sockaddr

Struct sockaddr_in

{

unsigned short sa_family;

har sa_data[14]

}

{ short sin_family;

Unsigned short sin_port;

Struct in_addr sin_addr;

Unsigned char sin_zero[8];

}

Sa_family:地址家族,

大多为AF_INET,

表示ip协议簇

Sa_data:协议地址

Sin_family:地址家族,

大多为AF_INET,表示ip协议簇

Sin_port:端口号

Sin_addr:存储ip地址

Sin_zero:填充用

  

在linux下

在windows下

  

Typedef struct in_addr

{ unsigned long s_addr;

}

Typedef struct in_addr

{

Union s_un{

Struct { char s_b1, s_b2, s_b3, s_b4;} s_un_b;

Struct { unsigned short s_w1,s_w2;}s_un_w;

Unsigned long s_addr;

}s_un

}in_addr

  

S_addr:存储的ip地址

  

 代码:

/*

*socket编程--tcp连接--服务器端

*/

#include <iostream>

using namespace std;

 

#include <winsock2.h>

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

 

#define DEFAULT_PORT 9090

 

int main()

{

//==========初始化socket库环境===========

WSADATA wsaData;

if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)

{

cout<<"WSAStartup failed"<<endl;

return -1;

}

 

//===========创建套接字=================

SOCKET sServer; //服务器套接字

sServer=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(INVALID_SOCKET==sServer)

{

cout<<"socket failed"<<endl;

WSACleanup();

return -1;

}

 

//===========绑定套接字=================

SOCKADDR_IN addrServer;

addrServer.sin_family=AF_INET;

addrServer.sin_port=htons(DEFAULT_PORT);

addrServer.sin_addr.s_addr=INADDR_ANY;

//addrServer.sin_addr.s_addr=htonl(INADDR_ANY);

//addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");

 

int val=bind(sServer,(LPSOCKADDR)&addrServer,sizeof(SOCKADDR_IN));

if(SOCKET_ERROR==val)

{

cout<<"bind failed"<<endl;

closesocket(sServer);

WSACleanup();

return -1;

}

 

//===========监听=======================

val=listen(sServer,SOMAXCONN);

if(SOCKET_ERROR==val)

{

cout<<"listen failed"<<endl;

closesocket(sServer);

WSACleanup();

return -1;

}

 

//===========接受客户端连接==============

SOCKET sClient;

sockaddr_in addrClient;

int addrClientLen=sizeof(addrClient);

sClient=accept(sServer,(sockaddr FAR*)&addrClient,&addrClientLen);

if(INVALID_SOCKET==sClient)

{

cout<<"accept failed"<<endl;

closesocket(sServer);

WSACleanup();

return -1;

}

 

//=========接收数据==========================

char buf[1024];

ZeroMemory(buf,1024);

val=0;

val=recv(sClient,buf,1024,0);

if(SOCKET_ERROR==val)

{

cout<<"recv failed"<<endl;

closesocket(sServer);

closesocket(sClient);

WSACleanup();

return -1;

}

cout<<buf<<endl;

 

//===========退出===========================

closesocket(sServer);

closesocket(sClient);

WSACleanup();

 

return 0;

}

 

 

/*

*socket编程--tcp连接--客户端

*/

#include <iostream>

using namespace std;

 

#include <winsock2.h>

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

 

#define DEFAULT_PORT 9090

#define BUF_SIZE 1024

int main()

{

 

SOCKET sHost; //服务器套接字

SOCKADDR_IN servAddr; //服务器地址

char buf[BUF_SIZE]; //接受数据缓冲区

int retVal;

 

//=========创建套接字====================

WSADATA wsd; //WSADATA变量

if(WSAStartup(MAKEWORD(1,0),&wsd)!=0)

{

cout<<"WSAStartup failed!"<<endl;

return -1;

}

if((int)LOBYTE(wsd.wVersion)!=1 || (int)HIBYTE(wsd.wVersion)!=0)

{

cout<<"version error!"<<endl;

return -1;

};

cout<<"WSAStartup ok......"<<endl;

 

//===========建立套接字=================

sHost=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(INVALID_SOCKET==sHost)

{

cout<<"socket failed!"<<endl;

WSACleanup();

return -1;

}

cout<<"socket ok......"<<endl;

 

//=============连接服务器=================

servAddr.sin_family =AF_INET;

servAddr.sin_addr .s_addr=inet_addr("127.0.0.1");

servAddr.sin_port =htons(DEFAULT_PORT);

 

retVal=connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr));

if(SOCKET_ERROR==retVal)

{

cout<<"connect failed!"<<endl;

closesocket(sHost);

WSACleanup();

return -1;

}

cout<<"connect success!"<<endl;

 

//==============发送数据===================

 

ZeroMemory(buf,BUF_SIZE);

strcat(buf,"hello");

 

retVal=send(sHost,buf,strlen(buf),0);

if(SOCKET_ERROR==retVal)

{

cout<<"send failed!"<<endl;

closesocket(sHost);

WSACleanup();

return -1;

}

cout<<"send "<<retVal<<" bytes."<<endl;

cout<<"they are:"<<buf<<endl;

 

ZeroMemory(buf,BUF_SIZE);

 

//=============接收数据==============

retVal=recv(sHost,buf,BUF_SIZE,0);

if(SOCKET_ERROR==retVal)

{

printf("recv failed!\n");

closesocket(sHost);

WSACleanup();

return -1;

}

cout<<"recv access,recv "<<retVal<<" bytes,they are:"<<endl;

cout<<buf<<endl;

 

 

 

//--------退出

shutdown(sHost,SD_BOTH);

closesocket(sHost);

WSACleanup();

cout<<"closed"<<endl;

return 0;

}

原文地址:https://www.cnblogs.com/mutou3221/p/3063373.html