创建套接字,面向连接通信
2012-03-06 21:48
399 查看
套接字是传输提供程序的句柄,是一个独立类型,SOCKET类型
socket WSASocket这两个函数可以用来创建套接字
服务器API函数
1.绑定 bind
一旦创建了某种协议的套接字,必须将套接字绑定到一个已知的地址
一旦出错,bind返回SOCKET_ERROR
2.监听 listen
接下来要做的是将套接字置于监听模式。
3.接收连接 accept
accept WSAAccept AcceptEx可以接受连接
编写一个能够接受TCP/IP连接的服务器
客户端API函数
TCP状态:对每一个套接字来说,它的初始状态都是CLOSED。若客户机初始化一个连接就会向服务器发送一个SYN包,同时客户机将套接字状态置为SYN_SENT。服务器收到一个SYN包后,会发出一个SYN_ACK包,客户机需要发送一个ACK包对它作出响应。此时客户机将套接字处于ESTABLISHED状态,如果服务器一直不发送SYN_ACK包,客户机就会超时,并返回CLOSED状态。
若服务器的套接字同本地接口及端口绑定起来,并在上面进行监听,那么套接字状态就是LISTEN。客户机试图与服务器连接时,服务器就会收到一个SYN包,并用一个SYN_ACK包作为回应,服务器套接字状态就会变成SYN_RCVD,最好客户机发出一个ACK包,它将使服务器套接字置于ESTABLISHED状态。
一旦应用程序处于ESTABLISHED状态,就可以通过两种方法关闭它。如果是应用程序来关闭,便叫做主动套接字关闭;否则就是被动的。若主动关闭,应用程序会发出一个FIN包。应用程序调用closesocket或shutdown时,会向通信对方发出一个FIN包,而且套接字状态将变为FIN_WAIT_1。正常情况下,通信对方会用一个ACK包作为回应,套接字状态将变为FIN_WAIT_2。如果通信对方也关闭了连接,它会发出一个FIN包,我们的机器则会以一个ACK包作为回应,并将套接字状态置为TIME_WAIT。
被动关闭时,应用程序会从对方那里收到一个FIN包,并用一个ACK包作为回应,此时应用程序的套接字会变为CLOSE_WAIT状态。由于对方已经关闭自己,它不再发送数据。而应用程序却不同,它能一直发送数据,直到它自己关闭连接为止。要想连接终端,应用程序需要发出自己的FIN包,令应用程序套接字置于LAST_ACK,应用程序从对方接收到一个ACK包后,它的套接字就会变成CLOSEED状态。
connect
套接字连接通过调用connect,WSAConnect,ConnectEx函数来完成
演示一个客户端:
数据传输
发送数据API send WSASend函数
接收数据API recv WSARecv函数
必须牢记着一点:所有关系到收发数据的缓冲区都属于简单的char类型,即面向字节的数据。
所有收发函数返回的错误都是SOCKET_ERROR,可以用WSAGetLastError来获得错误信息。
发送函数 WSASendDisconnect
这个函数很特殊,一般不用
函数WSASendDisconnect起初将套接字置于关闭状态,并发送端口的数据
在建立连接的套接字上通过recv来接收数据
尽量把所有的数据都复制到自己的缓冲区中,并在那里操作数据。
当挂起数据大于所提供的缓冲区时,缓冲区会尽量的让数据填满,这时,recv调用会产生WSAEMSGSIZE错误。注意,消息大小的错误是在面向消息的协议时发生,而流协议则把传入的数据缓存下来,并尽量返回应用程序所需要的数据,即使挂起的数据比提供的缓冲区大,因此对于流协议就不会碰到WSAEMSGSIZE错误。
中断连接
一旦完成套接字连接,就必须关闭它,并释放关联到这个套接字上的所有资源。先用shutdown关闭连接,在利用closesocket释放关联到套接字上的资源。
closesocket 用来关闭套接字
socket WSASocket这两个函数可以用来创建套接字
SOCKET socket( int af, int type, int protocol );
服务器API函数
1.绑定 bind
一旦创建了某种协议的套接字,必须将套接字绑定到一个已知的地址
int bind( SOCKET s, const struct sockaddr FAR* name, int namelen ); //s是等待客户连接的那个套接字 SOCKET s; SOCKADDR_IN tcpaddr; int port = 5050; s = socket(AF_INET, SOCK_STREAM, IPPORTO_TCP); tcpaddr.sin_family = AF_INET; tcpaddr.sin_port = htons(port); tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(s, (SOCKADDR *)&tcpaddr, sizeof(tcpaddr));
一旦出错,bind返回SOCKET_ERROR
2.监听 listen
接下来要做的是将套接字置于监听模式。
int listen( SOCKET s;//被绑定的套接字 int backlog//指定了被搁置的连接最大队列长度 );
3.接收连接 accept
accept WSAAccept AcceptEx可以接受连接
SOCKET accept( SOCKET s,//被绑定的套接字,它处于监听模式 struct sockaddr FAR* addr,//有效的SOCKADDR_IN地址 int FAR* addrlen//SOCKADDR_IN结构长度 );
编写一个能够接受TCP/IP连接的服务器
#include <winsock2.h> void main(void) { WSAData wsaData; SOCKET ListenSocket; SOCKET NewSocket; SOCKADDR_IN ServerAddr; SOCKADDR_IN ClientAddr; int port = 5050; //初始化winsock版本 WSAStartup(MAKEWORD(2,2), &wsaData); ListenSocket = socket(AF_INET, SOCK_STREAM, IPPORTO_TCP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(port); ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(ListenSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)); listen(ListenSocket, 5); NewSocket = accept(ListenSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen); //.. closesocket(NewSocket); closesocket(ServerSocket); WSACleanup(); }
客户端API函数
TCP状态:对每一个套接字来说,它的初始状态都是CLOSED。若客户机初始化一个连接就会向服务器发送一个SYN包,同时客户机将套接字状态置为SYN_SENT。服务器收到一个SYN包后,会发出一个SYN_ACK包,客户机需要发送一个ACK包对它作出响应。此时客户机将套接字处于ESTABLISHED状态,如果服务器一直不发送SYN_ACK包,客户机就会超时,并返回CLOSED状态。
若服务器的套接字同本地接口及端口绑定起来,并在上面进行监听,那么套接字状态就是LISTEN。客户机试图与服务器连接时,服务器就会收到一个SYN包,并用一个SYN_ACK包作为回应,服务器套接字状态就会变成SYN_RCVD,最好客户机发出一个ACK包,它将使服务器套接字置于ESTABLISHED状态。
一旦应用程序处于ESTABLISHED状态,就可以通过两种方法关闭它。如果是应用程序来关闭,便叫做主动套接字关闭;否则就是被动的。若主动关闭,应用程序会发出一个FIN包。应用程序调用closesocket或shutdown时,会向通信对方发出一个FIN包,而且套接字状态将变为FIN_WAIT_1。正常情况下,通信对方会用一个ACK包作为回应,套接字状态将变为FIN_WAIT_2。如果通信对方也关闭了连接,它会发出一个FIN包,我们的机器则会以一个ACK包作为回应,并将套接字状态置为TIME_WAIT。
被动关闭时,应用程序会从对方那里收到一个FIN包,并用一个ACK包作为回应,此时应用程序的套接字会变为CLOSE_WAIT状态。由于对方已经关闭自己,它不再发送数据。而应用程序却不同,它能一直发送数据,直到它自己关闭连接为止。要想连接终端,应用程序需要发出自己的FIN包,令应用程序套接字置于LAST_ACK,应用程序从对方接收到一个ACK包后,它的套接字就会变成CLOSEED状态。
connect
套接字连接通过调用connect,WSAConnect,ConnectEx函数来完成
int connect( SOCKET s,//即将在上面建立连接的有效的TCP套接字 const struct sockaddr FAR* name, int namelen );
演示一个客户端:
#include <winsock2.h> void main(void) { WSADATA wsaData; SOCKET s; SOCKADDR_IN addr; int port = 5050; WSAStartup(MAKEWORD(2,2), &wsaData); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr("123.123.123.123"); //... connect(s, (SOCKADDR*)&addr, sizeof(addr)); closesocket(s); WSACleanup(); }
数据传输
发送数据API send WSASend函数
接收数据API recv WSARecv函数
必须牢记着一点:所有关系到收发数据的缓冲区都属于简单的char类型,即面向字节的数据。
所有收发函数返回的错误都是SOCKET_ERROR,可以用WSAGetLastError来获得错误信息。
int send( SOCKET s,//用于发送数据的套接字 const char FAR* buf,//指向字符数据的缓冲区指针,缓冲区中包含发送的数据 int len,//缓冲区内的字符数 int flags ); //顺利的情况下,send将返回发送的字节数,若发送错误则返回SOCKET_ERRPR
int WSASend( SOCKET s,//连接会话的套接字 LPWSABUF lpBuffer,//指向一个或多个WSABUF结构的指针 DWORD dwBufferCount,//指明传递的WSABUF的数量 LPDWORD lpNumberOfBytesSend,//指向DOWRD指针,其中包含已发送的字节总数 DWORD dwFlags, LPWSAOVERLAPPED lpOverLapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); //lpNumberOfBytesSend设为写入的字节数,执行成功是该函数返回0,否则返回SOCK_ERROR
发送函数 WSASendDisconnect
这个函数很特殊,一般不用
int WSASendDisconnect( SOCKET s, LPWSABUF lpOutboundDisconnectData );
函数WSASendDisconnect起初将套接字置于关闭状态,并发送端口的数据
在建立连接的套接字上通过recv来接收数据
int recv( SOCKET s,//准备用来接收数据的套接字 char FAR* buf,//用于接收数据的字符缓冲区 int len,//准备接受的字节数或者缓冲区的长度 int flags );
尽量把所有的数据都复制到自己的缓冲区中,并在那里操作数据。
当挂起数据大于所提供的缓冲区时,缓冲区会尽量的让数据填满,这时,recv调用会产生WSAEMSGSIZE错误。注意,消息大小的错误是在面向消息的协议时发生,而流协议则把传入的数据缓存下来,并尽量返回应用程序所需要的数据,即使挂起的数据比提供的缓冲区大,因此对于流协议就不会碰到WSAEMSGSIZE错误。
int WSARecv( SOCKET s,//建立连接的套接字 LPWSABUF lpBuffers,//用来接收数据的缓冲 DWORD dwBufferCount, LPWORD lpNumberOfBytesRecvd, //指向这个函数调用从收到的字节数 LPWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
中断连接
一旦完成套接字连接,就必须关闭它,并释放关联到这个套接字上的所有资源。先用shutdown关闭连接,在利用closesocket释放关联到套接字上的资源。
int shutdown( SOCKET s, int how ); //how 可以是SD_RECEIVE,SD_SEND,SD_BOTH //SD_RECEIVE表示不允许再调用接收函数 //SD_SEND表示不允许再调用发送函数 //SD_BOTH表示取消两端的收发操作
closesocket 用来关闭套接字
int closesocket(SOCKET s);
相关文章推荐
- Windows下面向连接的套接字通信
- 面向连接的通信(LINUX)
- 面向链接套接字和无连接套接字的区别
- C#网络编程之面向连接的套接字
- Windows SOCKET编程 2-----(面向连接的通信TCP)---客户端
- 网络通信中基于套接字输入流和输出流的创建
- android wifi热点的创建以及连接通信(华为T8951 Google GALAXY Nexus 测试通过)
- UNIX domain中面向连接通信实现实例
- 网络通信过程 及TCP/UDP 面向连接?
- 基于 TCP (面向连接)和无连接UDP协议的 socket 套接字编程
- 【进程通信】popen与pclose,创建一个管道连接到另一个进程中
- nginx源代码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接
- TCPIP-TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议
- 简单实现如何使用 Socket 类实现面向连接的通信。
- NDK Socket编程:面向连接的通信(tcp)
- nginx源码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接
- 客服端:提示无法连接到安全服务器,套接字创建失败
- Redis源码剖析和注释(二十)--- 网络连接库剖析(client的创建/释放、命令接收/回复、Redis通信协议分析等)
- 套接字编程3 ------ 一个面向连接的SERVER/CLIENT综合实例
- Android 蓝牙通信开发(二) 创建蓝牙连接