Winsock编程流程
来源:互联网 发布:解剖软件 编辑:程序博客网 时间:2024/05/17 01:23
本文参考了《Window程序设计》加些自己的理解,写下本文以便加深对winsock的理解。
Winsock的编程一般步骤是固定的:
1.Winsock库的装入,初始化和释放。
2.套接字的创建和关闭。
3.绑定套接字到指定IP地址和端口号。
4.设置套接字进入监听状态。
5.接收连接请求。
6.收发数据。
1.Winsock库的装入、初始化和释放:
所有的WinSock函数都是从socket的函数库里导出来的。在MSVC中是从WS2_32.DLL文件中,在MinGW的gcc中是.a的文件。
所以在MS的vc或者vs中使用socket函数需要包含相应的文件
#pragma comment(lib, "wscok32.lib")
在使用MinGW的gcc的(如dev-c++),在gcc里是没有 #pragma comment(lib, "Winsock.lib") 这种预编译库指令的
另外gcc使用的静态库也不是用.lib,而是.a 。
WSAStartup必须是winsock首先调用的函数,它允许应用程序制定所需要的Windows Sockets API的版本,获取特定Winsock实现的详细信息。
仅当使用这个函数成功之后,应用程序才可以调用其它的Winsock API。
// 初始化套接字动态库WSADATA wsaData;if ( WSAStartup(MAKEWORD(2, 2), &wsaData) != 0 ) {printf( "winsock load faild!\n" );return -1;}
每一个对WSAStartup的调用都必须对一个WSACleanup的调用,此函数释放Winsock库。
WSACleanup(); // 资源释放
2.套接字的创建和关闭:
使用套接字之前,必须调用socket函数创建一个套接字的对象,此函数调用成功将返回套接字的句柄。
SOCKET Server = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );if ( Server == INVALID_SOCKET ) {printf( "socket faild!\n" );WSACleanup();return -1;}
创建socket对象的函数原型:
SOCKET socket(int af, // 用来指定套接字使用的地址格式,Winsock中只支持AF_INET int type, // 用来指定套接字的类型 int protocol // 配合type参数使用,指定协议类型,可以是IPPROTO_TCP等 );
type 参数用来指定套节字的类型。套节字有流套接字、数据报套节字和原始套节字等,
下面是常见的几种套节字类型定义:
SOCK_STREAM 流套节字,使用 TCP 协议提供有连接的可靠的传输
SOCK_DGRAM数据报套节字,使用 UDP 协议提供无连接的不可靠的传输
SOCK_RAW 原始套节字,WinSock 接口并不使用某种特定的协议去封装它,而是有程序自行处理数据报以及协议首部
函数执行失败的时候返回INVALID_SOCKET(即-1)。
当不使用socket对象的时候应该使用closesocket函数将它关闭,如果没有发生错误,函数返回0,否则返回SOCKET_ERROR.
closesocket( Client );
3.绑定套接字到指定的IP地址和端口号:
socket程序主要用于两台电脑间的通讯,准确的说应该是两台电脑中的进程的通讯,仅使用ip地址只能确定对方的电脑而不能确定应用进程,所以需要加上端口号用来确定进程。
为套接字关联本地地址的函数是bind,函数原型如下。
int bind(SOCKET s,// 套接字句柄 const struct sockaddr* name,// 需要关联的本地地址 int namelen // 地址长度 );
bind 函数用在没有建立连接的套节字上,它的作用是绑定面向连接的或者无连接的套节字。当一个套节字被 socket 函数创建以后,他存在于指定的地址家族里,但是它是未命名的。bind 函数通过安排一个本地名称到未命名的 socket 建立此 socket 的本地关联。
本地名称包含 3个部分:主机地址、协议号(分别为 UDP 或 TCP)和端口号。
// 服务端地址 sockaddr_in addrServ;addrServ.sin_family = AF_INET; // htons: 转化一个 u_short 类型从主机字节顺序到 TCP/IP 网络字节顺序(大小端存储) host to net short addrServ.sin_port = htons( 9999 );addrServ.sin_addr.s_addr = htonl( INADDR_ANY ); // 绑定套接字 if ( bind( Server, ( const struct sockaddr* )&addrServ, sizeof(addrServ) ) == SOCKET_ERROR ) {printf( "bind faild!\n" );closesocket( Server );WSACleanup(); return -1;} printf("Server is On IP:[%s],port:[%d]\n",inet_ntoa(addrServ.sin_addr),ntohs(addrServ.sin_port));
sockaddr_in 结构中的 sin_familly 字段用来指定地址家族,该字段和 socket 函数中的 af 参数的含义相同,所以惟一可以使用的值就是 AF_INET。
sin_port 字段和 sin_addr 字段分别指定套节字需要绑定的端口号和 IP 地址。放入这两个字段的数据的字节顺序必须是网络字节顺序。
由于网络字节顺序和 Intel CPU 的字节顺序刚好相反,所以必须首先用 htons 函数进行转换。如果应用程序不关心所使用的地址,可以为互联网地址指定 INADDR_ANY,为端口号指定 0。如果互联网地址等于 INADDR_ANY,系统会自动使用当前主机配置的所有 IP 地址,这简化了程序设计;如果端口号等于 0,程序执行时系统会分配一个惟一的端口号到这个应用程序,其值在 1024 到 5000 之间。应用程序可以在 bind 之后使用 getsockname 来知道为它分配的地址。但是要注意,直到套节字连接上之后 getsockname 才可能填写互联网地址,因为对一个主机来说可能有多个地址是可用的。
4.设置套接字进入监听状态:
listen函数设置套接字进入监听状态:
int listen(SOCKET s,// socket句柄 int backlog // 最大监听客户端数目 );
函数出现错误会返回SOCKET_ERROR。
5.接受连接请求:
accept函数用于接收到来的连接:
SOCKET accept(SOCKET s,// socket句柄 struct sockaddr* addr,// 一个指向sockaddr_in结构的指针,用于获取对方地址信息 int* addrlen// 一个指向地址长度的指针 );该函数在 s 上取出未处理连接中的第一个连接,然后为这个连接创建一个新的套节字,返回它的句柄。新创建的套节字是处理实际连接的套节字,它与 s 有相同的属性。
程序默认工作在阻塞模式下,这种方式下如果没有未处理的连接存在,accept 函数会一直等待下去直到有新的连接发生才返回。
客户端程序在创建套接字之后,需要调用connect函数请求连接服务器:
int connect(SOCKET s,const struct sockaddr* name, // 一个指向sockaddr_in结构的指针,包含了要连接的服务器的信息 int namelen// sockaddr_in结构的长度 );
6.收发数据:
对于流套接字,一般使用send和recv函数收发数据。
int send(SOCKET s,const char* buf,// 要发送的数据 int buflen,// 数据长度 int flags// 指定调用方式,通常设为 0 );
int recv(SOCKET s,const char* buf, // 接收数据的数组 int buflen, // 缓冲区大小 int flags // 0);
send 函数在一个连接的套节字上发送缓冲区内的数据,返回发送数据的实际字节数。
recv函数从对方接收数据,并存储它到指定的缓冲区。
flags 参数在这两函数中通常设为 0。
在阻塞模式下,send 将会阻塞线程的执行直到所有的数据发送完毕(或者一个错误发生),
recv 函数将返回尽可能多的当前可用信息,一直到缓冲区指定的大小。
- Winsock编程流程
- Winsock 编程流程
- Winsock编程流程
- WinSock编程流程(2)- UDP
- Winsock编程流程(1)-TCP/IP
- winsock流程
- winsock编程
- WinSock编程
- Winsock编程
- Winsock编程
- winsock编程
- Winsock编程
- winsock编程
- Winsock编程
- Winsock编程
- winsock编程
- winsock编程
- winsock编程
- docker基础(一)
- 【CMake】已有项目添加JNI支持
- Storm Topologies 示例——(结合Maven使用storm-starter)
- 06.14 memcached缓存服务
- bzoj3781 小B的询问(莫队)
- Winsock编程流程
- appium +夜神模拟器 java代码sendkeys 无法在模拟器输入中文
- Json学习笔记(三)-前端json字符串互转(4种转换方式)
- Spark的一些操作
- 将txt文本中的图片路径的图片读到某文件夹下
- oracle删除DBF文件
- 重启ORACLE数据库
- linux创建软连接
- JDK动态代理