winsock编程问题
2006-01-24 12:01
204 查看
套接字,就是一个指向传输提供者的句柄。Wi n 3 2中,套接字不同于文件描述符,所以它是一个独立的类型—S O C K E T。
套接字是由两个函数建立的:
SOCKET WSASocket(int af,int type,int protocal,LPWSAPROTOCOL_INFO lpProtocolInfor,GROUP g,DWORD dwFlags);
SOCKET socket(int af,int type, int protocal);
第一个参数a f,是协议的地址家族。比如,如果想建立一个U D P或T C P套接字,可用常量
A F _ I N E T来指代互联网协议( I P)。
第二个参数t y p e,是协议的套接字类型。套接字的类型可以是下面五个值: S O C K _ S T R E A M、S O C K _ D G R A M、S O C K _ S E Q PA C K E T、S O C K _ R AW和S O C K _ R D M。
第三个参数是p r o t o c o l。指定的地址家族和套接字类型有多个条目时,就可用这个字段来限定使用特定传输.
如果在W S A S o c k e t函数时,已经利用W S A E n u m P r o t o c o l s列举了所有协议,就可选定一个
W S A P R O TO C O L _ I N F O结构,并将它当作l p P r o t o c o l I n f o参数投递到W S A S o c k e t。之后,若
在前三个参数(a f、t y p e和p r o t o c o l)中都指定常量F R O M _ P R O TO C O L _ I N F O,就会转而采用W S A P R O TO C O L _ I N F O结构中提供的那三个值。以上便是教大家如何指定一个准确无误的协议条目。
最后两个W S A S o c k e t标志很简单。组参数始终为0,因为目前尚无可支持套接字组的Wi n s o c k版本。
Winsock的初始化
每个Wi n s o c k应用都必须加载Winsock DLL的相应版本。如果调用Wi n s o c k之前,没有加载
Wi n s o c k库,这个函数就会返回一个S O C K E T _ E R R O R,错误信息是W S A N O T I N I T I A L I S E D。
加载Wi n s o c k库是通过调用W S A S t a r t u p函数实现的。这个函数的定义如下:
int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
w Ve r s i o n R e q u e s t e d参数用于指定准备加载的Wi n s o c k库的版本。高位字节指定所需要的Wi n s o c k库的副版本,而低位字节则是主版本。然后,可用宏M A K E W O R D ( X , Y )(其中,x是高位字节, y是低位字节)方便地获得w Ve r s i o n R e q u e s t e d的正确值。
l p W S A D a t a参数是指向L P W S A D ATA结构的指针, W S A S t a r t u p用其加载的库版本有关的信息.
客户机需要通过T C P或U D P和服务器通信时,必须指定服务器的I P地址和服务端口号。另外,服务器打算监听接入客户机请求时,也必须指定一个I P地址和一个端口号。Wi n s o c k中,应用通过S O C K A D D R _ I N结构来指定I P地址和服务端口信息,该结构的格式如下:
struct sockaddr_in
{
short sin_family;
u_shot sin_port;
struck in_addr sin_addr;
char sin_zero[80]
}
创建套接字:
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
或:server = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
服务器API:
1.BIND
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);
一旦出错, b i n d 就会返回S O C K E T _ E R R O R 。对b i n d 来说,最常见的错误是
W S A E A D D R I N U S E。如使用的是T C P / I P,那么W S A E A D D R I N U S E就表示另一个进程已经同
本地I P接口和端口号绑定到了一起,或者那个I P接口和端口号处于T I M E _ WA I T状态。假如你
针对一个套接字调用b i n d,但那个套接字已经绑定,便会返回W S A E F FA U LT错误。
2.LISTEN
int listen(SOCKET s,int backlog);
第一个参数同样是限定套接字。b a c k l o g参数指定了正在等待连接的最大队列长度。
与l i s t e n对应的错误是非常直观的。到目前为止,最常见的错误是W S A E I N VA L。该错误
通常意味着,你忘记在l i s t e n之前调用b i n d。否则,与b i n d调用相反,使用l i s t e n时可能收到
W S A E A D D R I N U S E。这个错误通常是在进行b i n d调用时发生的。
3. accept和W S A A c c e p t
现在,我们已做好了接受客户连接的准备。这是通过a c c e p t或W S A A c c e p t函数来完成的。
a c c e p t格式如下:
SOCKET accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);
Winsock 2引入了一个名为W S A A c c e p t的函数。它能根据一个条件函数的返回值,选择性
地接受一个连接。这个新函数的定义如下:
SOCKET WSAAccept(SOCKET s, struct sockaddr FAR* addr,LLPINT addrlen, LPCONDITIONPROC lpfnCondition,DWORD dwCallbackData);
客户机API:
1。c o n n e c t函数和W S A C o n n e c t函数
这是通过调用c o n n e c t函数或W S A C o n n e c t函数来完成的。我们先来
看看该函数的Winsock 1版本,其定义如下:
int connect(SOCKET s,const struct sockaddr FAR* name,int namelen);
Winsock 2版本中,它的定义是这样的:
int WSAConnect(SOCKET s,const struct sockaddr FAR* name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
如果你想连接的计算机没有监听指定端口这一进程, c o n n e c t调用就会失败,并发生错误
W S A E C O N N R E F U S E D。另一个错误可能是W S A E T I M E D O U T,这种情况一般发生在试图连
接的计算机不能用时(亦可能因为到主机之间的路由上出现硬件故障或主机目前不在网上)。
2. send和W S A S e n d
要在已建立连接的套接字上发送数据,第一个可用的A P I函数是s e n d,其原型为:
int send(SOCKET s,const char FAR* buf,int len,int flags);
对返回数据而言,s e n d返回发送的字节数;若发生错误,就返回S O C K E T _ E R R O R。常见
的错误是W S A E C O N N A B O RT E D,这一错误一般发生在虚拟回路由于超时或协议有错而中断
的时候。发生这种情况时,应该关闭这个套接字,因为它不能再用了。远程主机上的应用通
过执行强行关闭或意外中断操作重新设置虚拟虚路时,或远程主机重新启动时,发生的则是
W S A E C O N N R E S E T错误。再次提醒大家注意,发生这一错误时,应该关闭这个套接字。最
后一个常见错误是W S A E T I M E O U T,它发生在连接由于网络故障或远程连接系统异常死机而
引起的连接中断时。
send API函数的Winsock 2版本是W S A S e n d,它的定义如下:
int WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOVERlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletion
a86b
ROUTINE);
这个套接字是一个连接会话的有效句柄。第二个参数是指向一个或多个W S A B U F结构的
指针。它既可是一个独立的结构,又可以是一组结构。第三个参数指明准备投递的W S A B U F
结构数。记住,每个W S A B U F结构本身就是一个字符缓冲和缓冲长度。为何打算同时发送多
个缓冲呢?也许大家不太明白其中的原因。这就是我们稍后要讲的“分散集中I / O模式”;但
是,在一个已建立连接的套接字上利用多缓冲来发送数据时,顺序是从第一个到最后一个
W S A B U F结构。l p N u m b e r O f B y t e s S e n t是指向D W O R D(是W S A S e n d调用返回的)的指针,其中
包含字节总发送数。d w F l a g s参数相当于它在s e n d中的等同物。最后两个参数—l p O v e r l a p p e d
和l p C o m p l e t i o n R O U T I N E—用于重叠I / O.
4 recv和W S A R e c v
对在已连接套接字上接受接入数据来说, r e c v函数是最基本的方式。它的定义如下:
int recv(SOCKET s,char FAR* buf,int len, int flags);
W S A R e c v函数在r e c v的基础上增加了一些新特性。比如说重叠I / O和部分数据报通知。
W S A R e c v的定义如下:
int WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE);
------------------------------------------
TCP server示例
#include <windows.h>
#include <iostream>
#include <winsock.h>
#pragma comment( lib, "Ws2_32.lib" )
using namespace std;
const int MY_ERROR = -1;
int main( )
{
WSADATA wsaData;
//初始化Windows Socket 库
if( WSAStartup(MAKEWORD( 2, 2 ), &wsaData)!=0 )
{
cout<<"Error in WSAStartup";
return MY_ERROR;
}
//创建一个socket->bind->listen->accept(阻塞)
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server==INVALID_SOCKET)
{
return 0;
}
sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(8080);
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if( bind(server, (sockaddr*)(&local), sizeof(local))!=0 )
{
cout<<"Error in bind";
return MY_ERROR;
}
if( listen(server, 10)!=0 )
{
cout<<"Error in listen";
return MY_ERROR;
}
SOCKET client;
sockaddr_in from;
int fromLen = sizeof(from);
memset(&from, 0, fromLen);
cout<<"waiting for connect...";
client = accept(server, (sockaddr*)(&from), &fromLen);
char temp[512];
sprintf(temp,"Your IP is %s/r/n",inet_ntoa(from.sin_addr));
send(client, temp, strlen(temp), 0);
cout << "Connection from " << inet_ntoa(from.sin_addr) <<"/r/n";
closesocket(client);
closesocket(server);
WSACleanup();
return 0;
}
------------------------------------------
套接字是由两个函数建立的:
SOCKET WSASocket(int af,int type,int protocal,LPWSAPROTOCOL_INFO lpProtocolInfor,GROUP g,DWORD dwFlags);
SOCKET socket(int af,int type, int protocal);
第一个参数a f,是协议的地址家族。比如,如果想建立一个U D P或T C P套接字,可用常量
A F _ I N E T来指代互联网协议( I P)。
第二个参数t y p e,是协议的套接字类型。套接字的类型可以是下面五个值: S O C K _ S T R E A M、S O C K _ D G R A M、S O C K _ S E Q PA C K E T、S O C K _ R AW和S O C K _ R D M。
第三个参数是p r o t o c o l。指定的地址家族和套接字类型有多个条目时,就可用这个字段来限定使用特定传输.
如果在W S A S o c k e t函数时,已经利用W S A E n u m P r o t o c o l s列举了所有协议,就可选定一个
W S A P R O TO C O L _ I N F O结构,并将它当作l p P r o t o c o l I n f o参数投递到W S A S o c k e t。之后,若
在前三个参数(a f、t y p e和p r o t o c o l)中都指定常量F R O M _ P R O TO C O L _ I N F O,就会转而采用W S A P R O TO C O L _ I N F O结构中提供的那三个值。以上便是教大家如何指定一个准确无误的协议条目。
最后两个W S A S o c k e t标志很简单。组参数始终为0,因为目前尚无可支持套接字组的Wi n s o c k版本。
Winsock的初始化
每个Wi n s o c k应用都必须加载Winsock DLL的相应版本。如果调用Wi n s o c k之前,没有加载
Wi n s o c k库,这个函数就会返回一个S O C K E T _ E R R O R,错误信息是W S A N O T I N I T I A L I S E D。
加载Wi n s o c k库是通过调用W S A S t a r t u p函数实现的。这个函数的定义如下:
int WSAStartup(WORD wVersionRequested,LPWSADATA lpWSAData);
w Ve r s i o n R e q u e s t e d参数用于指定准备加载的Wi n s o c k库的版本。高位字节指定所需要的Wi n s o c k库的副版本,而低位字节则是主版本。然后,可用宏M A K E W O R D ( X , Y )(其中,x是高位字节, y是低位字节)方便地获得w Ve r s i o n R e q u e s t e d的正确值。
l p W S A D a t a参数是指向L P W S A D ATA结构的指针, W S A S t a r t u p用其加载的库版本有关的信息.
客户机需要通过T C P或U D P和服务器通信时,必须指定服务器的I P地址和服务端口号。另外,服务器打算监听接入客户机请求时,也必须指定一个I P地址和一个端口号。Wi n s o c k中,应用通过S O C K A D D R _ I N结构来指定I P地址和服务端口信息,该结构的格式如下:
struct sockaddr_in
{
short sin_family;
u_shot sin_port;
struck in_addr sin_addr;
char sin_zero[80]
}
创建套接字:
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
或:server = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
服务器API:
1.BIND
int bind(SOCKET s,const struct sockaddr FAR* name,int namelen);
一旦出错, b i n d 就会返回S O C K E T _ E R R O R 。对b i n d 来说,最常见的错误是
W S A E A D D R I N U S E。如使用的是T C P / I P,那么W S A E A D D R I N U S E就表示另一个进程已经同
本地I P接口和端口号绑定到了一起,或者那个I P接口和端口号处于T I M E _ WA I T状态。假如你
针对一个套接字调用b i n d,但那个套接字已经绑定,便会返回W S A E F FA U LT错误。
2.LISTEN
int listen(SOCKET s,int backlog);
第一个参数同样是限定套接字。b a c k l o g参数指定了正在等待连接的最大队列长度。
与l i s t e n对应的错误是非常直观的。到目前为止,最常见的错误是W S A E I N VA L。该错误
通常意味着,你忘记在l i s t e n之前调用b i n d。否则,与b i n d调用相反,使用l i s t e n时可能收到
W S A E A D D R I N U S E。这个错误通常是在进行b i n d调用时发生的。
3. accept和W S A A c c e p t
现在,我们已做好了接受客户连接的准备。这是通过a c c e p t或W S A A c c e p t函数来完成的。
a c c e p t格式如下:
SOCKET accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);
Winsock 2引入了一个名为W S A A c c e p t的函数。它能根据一个条件函数的返回值,选择性
地接受一个连接。这个新函数的定义如下:
SOCKET WSAAccept(SOCKET s, struct sockaddr FAR* addr,LLPINT addrlen, LPCONDITIONPROC lpfnCondition,DWORD dwCallbackData);
客户机API:
1。c o n n e c t函数和W S A C o n n e c t函数
这是通过调用c o n n e c t函数或W S A C o n n e c t函数来完成的。我们先来
看看该函数的Winsock 1版本,其定义如下:
int connect(SOCKET s,const struct sockaddr FAR* name,int namelen);
Winsock 2版本中,它的定义是这样的:
int WSAConnect(SOCKET s,const struct sockaddr FAR* name,int namelen,LPWSABUF lpCallerData,LPWSABUF lpCalleeData,LPQOS lpSQOS,LPQOS lpGQOS);
如果你想连接的计算机没有监听指定端口这一进程, c o n n e c t调用就会失败,并发生错误
W S A E C O N N R E F U S E D。另一个错误可能是W S A E T I M E D O U T,这种情况一般发生在试图连
接的计算机不能用时(亦可能因为到主机之间的路由上出现硬件故障或主机目前不在网上)。
2. send和W S A S e n d
要在已建立连接的套接字上发送数据,第一个可用的A P I函数是s e n d,其原型为:
int send(SOCKET s,const char FAR* buf,int len,int flags);
对返回数据而言,s e n d返回发送的字节数;若发生错误,就返回S O C K E T _ E R R O R。常见
的错误是W S A E C O N N A B O RT E D,这一错误一般发生在虚拟回路由于超时或协议有错而中断
的时候。发生这种情况时,应该关闭这个套接字,因为它不能再用了。远程主机上的应用通
过执行强行关闭或意外中断操作重新设置虚拟虚路时,或远程主机重新启动时,发生的则是
W S A E C O N N R E S E T错误。再次提醒大家注意,发生这一错误时,应该关闭这个套接字。最
后一个常见错误是W S A E T I M E O U T,它发生在连接由于网络故障或远程连接系统异常死机而
引起的连接中断时。
send API函数的Winsock 2版本是W S A S e n d,它的定义如下:
int WSASend(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD dwFlags,LPWSAOVERLAPPED lpOVERlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletion
a86b
ROUTINE);
这个套接字是一个连接会话的有效句柄。第二个参数是指向一个或多个W S A B U F结构的
指针。它既可是一个独立的结构,又可以是一组结构。第三个参数指明准备投递的W S A B U F
结构数。记住,每个W S A B U F结构本身就是一个字符缓冲和缓冲长度。为何打算同时发送多
个缓冲呢?也许大家不太明白其中的原因。这就是我们稍后要讲的“分散集中I / O模式”;但
是,在一个已建立连接的套接字上利用多缓冲来发送数据时,顺序是从第一个到最后一个
W S A B U F结构。l p N u m b e r O f B y t e s S e n t是指向D W O R D(是W S A S e n d调用返回的)的指针,其中
包含字节总发送数。d w F l a g s参数相当于它在s e n d中的等同物。最后两个参数—l p O v e r l a p p e d
和l p C o m p l e t i o n R O U T I N E—用于重叠I / O.
4 recv和W S A R e c v
对在已连接套接字上接受接入数据来说, r e c v函数是最基本的方式。它的定义如下:
int recv(SOCKET s,char FAR* buf,int len, int flags);
W S A R e c v函数在r e c v的基础上增加了一些新特性。比如说重叠I / O和部分数据报通知。
W S A R e c v的定义如下:
int WSARecv(SOCKET s,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRecvd,LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE);
------------------------------------------
TCP server示例
#include <windows.h>
#include <iostream>
#include <winsock.h>
#pragma comment( lib, "Ws2_32.lib" )
using namespace std;
const int MY_ERROR = -1;
int main( )
{
WSADATA wsaData;
//初始化Windows Socket 库
if( WSAStartup(MAKEWORD( 2, 2 ), &wsaData)!=0 )
{
cout<<"Error in WSAStartup";
return MY_ERROR;
}
//创建一个socket->bind->listen->accept(阻塞)
SOCKET server;
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(server==INVALID_SOCKET)
{
return 0;
}
sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(8080);
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if( bind(server, (sockaddr*)(&local), sizeof(local))!=0 )
{
cout<<"Error in bind";
return MY_ERROR;
}
if( listen(server, 10)!=0 )
{
cout<<"Error in listen";
return MY_ERROR;
}
SOCKET client;
sockaddr_in from;
int fromLen = sizeof(from);
memset(&from, 0, fromLen);
cout<<"waiting for connect...";
client = accept(server, (sockaddr*)(&from), &fromLen);
char temp[512];
sprintf(temp,"Your IP is %s/r/n",inet_ntoa(from.sin_addr));
send(client, temp, strlen(temp), 0);
cout << "Connection from " << inet_ntoa(from.sin_addr) <<"/r/n";
closesocket(client);
closesocket(server);
WSACleanup();
return 0;
}
------------------------------------------
相关文章推荐
- Winsock编程中sin_port设定和抓包数据不一样的问题。
- 入门者的WinSock编程问题
- Eclipse下C语言的Socket编程(Winsock,gcc)问题总结
- 关于winodows下编程c++遇到的引用文件路径问题
- Java编程题目-4:数组操作问题
- spring入门编程问题集锦
- 编程中对于文件路径应该注意的问题
- 使用 ASP.NET 以编程方式检查规范化问题
- VS2010下MFC ActiveX控件与C#编程中间遇到的问题
- 编程连接远程SQL服务器出现问题及对策
- 2010/7/1网络编程常见问题总结
- 同步与异步 阻塞与非阻塞 WinSock编程
- Java网络编程(五)socket的半包,粘包与分包的问题
- 个人总结:嵌入式编程应该注意的问题
- [编程之美-10]字符串的包含问题
- SQL Server ->> CLR编程问题汇总
- 常见的几个Qt编程问题的处理
- 网络编程常见问题总结(1)
- **个人编程中提出的一些问题及解决办法**
- 编程之美 - 1.4 买书问题