- Siginificant functions
//IN SERVER 1. socket()//listening socket creat 2. bind()//bind 3. listen()// star to listen 5. socket=accept()//back a real sockt to communication 6. recv/send()//to recive and send data in socket 8. closesocket() //IN Client 1. socket()//only use to communication, they need't listen 2. cconnect() 3. recv/send()//to recive and send data in socket 4. closesocket()
1. SOCKET socket (int af, int type, int protocol);
- arguments
- af:标识一个地址家族,通常为AF_INET。
- type:标识套接字类型,SOCK_STREAM表示流式套字;SOCK_DGRAM表示数据报套接字;SOCK_RAW表示原始套接字。
- protocol:标识一个特殊的协议被用于这个套接字,通常为0,表示采用默认的TCP/IP协议
- return
socket()函数返回的套接字描述符的类型符SOCKET,它是Winsock中专门定义的一种新的数据类型,其定义为typedef u_int SOCKET;
是一个无符号整型数。 - error
创建套接字失败返回的常量INVALID_SOCKET的定义如下
#define INVALID_SOCKET (SOCKET)~0
是各二进制位全为1的一个无符号整数。不难看出,合法的套接字描述符的取值可以是0~INVALID_SOCKET-1之间的任何值。 - code
//建立一个socket sock_server = socket(AF_INET,SOCK_STREAM,0); if (sock_server==INVALID_SOCKET) { //socket建立失败 int errno=WSAGetLastError(); cout<<"创建套接字失败!错误代码:"<<errno<<endl; return 0; } else { //socket建立成功 cout<<"socket created ." <<sock_server<<endl; }
2. int bind(SOCKET s,struct sockaddr* name, int namelen);
- socket()函数在创建套接字时并没有为创建的套接字分配地址,因此服务器软件在创建了监听套接字之后,需要调用bind函数为其指定本机地址、协议和端口号。
- 将套接字绑定到一个已知的地址上。如果函数执行成功,返回值为0,否则为SOCKET_ERROR。
- arguments
- s:是一个套接字。
- name:是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口号。
- namelen:确定name缓冲区的长度。
- code
//band the IP interface struct sockaddr_in addr; addr.sin_family =AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); //允许套接字使用本机的任何IP if(bind(sock_server,(LPSOCKADDR)&addr,sizeof(addr))!=0) { printf("邦定失败!\n"); return 0; }
- explain
- IP address is
INADDR_ANY
, which meaning the IP address will be appoint by system. if you want appoint a IP address , you can replace theINADDR_ANY
to a 32bit single integer number.
- IP address is
3. int listen (SOCKET s, int backlog);
- listen()函数只能由服务器端使用,而且只适用于流式套接字,listen()函数用于将套接字置为监听模式
- arguments
- s:套接字。
- backlog:表示等待连接的最大队列长度。例,若设置backlog为3,当同时收到4个客户连接请求时,则前3个客户连接请求会放置在等待队列中,第4个客户端会得到错误信息。该参数值通常设置为常量SOMAXCONN,表示将连接等待队列的最大长度值设为一个最大的“合理”值,该值有底层开发者指定,WinSock2中,该值为5。
-
- code
if(listen(sock_server,SOMAXCONN)!=0) { cout<<"listen函数调用失败!\n"; return 0; }
4. SOCKET accept (SOCKET s, struct sockaddr * addr, int FAR* addrlen);
- 用于接受客户端的连接请求。
- aeguments
s:是一个套接字,它应处于监听状态。
addr:是一个sockaddr_in结构指针,包含一组客户端的端口号、IP地址等信息。
addrlen:用于接收参数addr的长度。 - error and return
- accept()函数返回一个已建立连接的新的套接字的描述符,即已连接套接字的描述符,服务器与本连接所对应客户端的所有后续通信,都应使用该套接字。原来的监听套接字仍然处于监听状态,可以继续接受其他客户的连接请求。
- 如果发生错误,将返回 INVALID_SOCKET
- 默认情况下,如果调用accept()时还没有客户的连接请求到达,accept()将不会返回,进程将阻塞,直到有客户与服务器建立了连接才会返回。
- code
int addr_len=sizeof(client_addr) SOCKET newsock = accept ( sock_server, (LPSOCKADDR)&client_addr, &addr_len); if(newsock ==INVALID_SOCKET) { cout<<"accept()函数调用失败!错误代码:"; cout<<WSAGetLastError()<<endl; }
5. int connect (SOCKET s, const struct sockaddr * name, int namelen);
- connect函数用于发送一个连接请求。若成功则返回0,否则为SOCKET_ERROR。用户可以通过WSAGetLastError得到其错误描述
- arguments
- s:标识一个套接字。
- name:套接字s想要连接的主机地址和端口号。
- namelen:name缓冲区的长度。
- code
struct sockaddr_in server_addr;
memset((void *)&server_addr,0,addr_len);
server_addr.sin_family =AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(“127.0.0.1”)
if(connect(sock_client, (LPSOCKADDR)&server_addr,addr_len)!=0)
{
printf(“连接失败\n”);
return 0;
}
```
6. int send(SOCKET s,const char * buf, int len, int flag s);
- 用于在已经建立连接的套接字上发送数据。
- arguments
- s: 标识一个套接字
- buf :是存放要发送数据的缓冲区
- len:标识缓冲区长度
- flags :用于控制数据发送的方式,通常取0,表示正常发送数据;如果取值为宏MSG_DONTROUT,则表示目标主机就在本地网络中,也就是与本机在同一个IP网段上,数据分组无须路由可直接交付目的主机,如果传输协议的实现不支持该选项则忽略该标志;如果该参数取值为宏MSG_OOB,则表示数据将按带外数据发送。
- notion
- 带外数据(Out Of Band ,OOB)本义是指那些使用与普通数据不同的另外的信道传送的一些特殊数据。带外数据一般都是一些重要的数据,通信协议通常能将这些数据快速地发送到对方
- TCP协议试图通过紧急数据机制来实现带外数据的功能,但紧急数据并不是真正意义上的带外数据,因为TCP并没有真正开辟一个新的信道进行数据传输,而是将这些数据放在普通的数据流中一起传输。
- 现在,TCP的带外数据功能基本已经是废弃的功能了。2011年发表的有关TCP的紧急数据的因特网标准RFC6093就强烈建议,新的应用不要再使用紧急数据机制。
- send()函数的返回值指示了实际发送的字节总数。默认情况下,send() 函数的调用会一直阻塞到发送了所有数据为止。
7. int recv (SOCKET s, char * buf, int len, int flags);
- 用于从连接的套接字中返回数据。该函数执行成功返回实际从套接字s读入到buf中的字节数。连接终止则返回0;否则返回SOCKET_ERROR错
- arguments
- s:标识一个套接字
- buf:是接收数据的缓冲区
- len:是buf的长度
- flags:表示函数的调用方式,一般取值0
- code
发送数据的例子 char msgbuf[]="The message to be sent"; send(s,msgbuf, sizeof(msgbuf), 0); 接收数据的例子 char msgbuffer[1000]; //保存收到数据的缓存区 if(recv(s, msgbuffer, sizeof(msgbuffer),0)<=0) std::cout<<"接受信息失败\n"; else std::cout<<"The message from client:\n"<<msgbuffer <<endl; //输出收到的信息
8. int closesocket (SOCKET s );
- 标识一个要被关闭的套接字
- 该函数执行成功返回0;否则返回SOCKET_ERROR错。