socket编程(一)
因为下载器涉及到socket的知识,就花了一天学习了。因为时间原因分成几部分。(这里记录上的是基于Windows平台的)
1 #include <stdio.h> 2 #include <winsock2.h> 3 #pragma comment (lib, "ws2_32.lib") //加载 ws2_32.dll 4 5 int main(){ 6 //初始化 DLL 7 WSADATA wsaData; 8 WSAStartup( MAKEWORD(2, 2), &wsaData); 9 10 //创建套接字 11 SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 12 13 //绑定套接字 14 sockaddr_in sockAddr; 15 memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充 16 sockAddr.sin_family = PF_INET; //使用IPv4地址 17 sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具体的IP地址 18 sockAddr.sin_port = htons(1234); //端口 19 bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); 20 21 //进入监听状态 22 listen(servSock, 20); 23 24 //接收客户端请求 25 SOCKADDR clntAddr; 26 int nSize = sizeof(SOCKADDR); 27 SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize); 28 29 //向客户端发送数据 30 char *str = "Hello World!"; 31 send(clntSock, str, strlen(str)+sizeof(char), NULL); 32 33 //关闭套接字 34 closesocket(clntSock); 35 closesocket(servSock); 36 37 //终止 DLL 的使用 38 WSACleanup(); 39 40 return 0; 41 }
AF_INET 表示使用 IPv4 地址 SOCK_STREAM 表示使用面向连接的数据传输方式
IPPROTO_TCP 表示使用 TCP 协议
第19行通过 bind() 函数将套接字 serv_sock 与特定的IP地址和端口绑定,IP地址和端口都保存在 sockaddr_in 结构体中。
socket() 函数确定了套接字的各种属性,bind() 函数让套接字与特定的IP地址和端口对应起来,这样客户端才能连接到该套接字。
第22行让套接字处于被动监听状态。所谓被动监听,是指套接字一直处于“睡眠”中,直到客户端发起请求才会被“唤醒”。
第27行的 accept() 函数用来接收客户端的请求。程序一旦执行到 accept() 就会被阻塞(暂停运行),直到客户端发起请求。
和普通文件一样,socket 在使用完毕后也要用 close() 关闭。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <WinSock2.h> 4 #pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll 5 6 int main(){ 7 //初始化DLL 8 WSADATA wsaData; 9 WSAStartup(MAKEWORD(2, 2), &wsaData); 10 11 //创建套接字 12 SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 13 14 //向服务器发起请求 15 sockaddr_in sockAddr; 16 memset(&sockAddr, 0, sizeof(sockAddr)); //每个字节都用0填充 17 sockAddr.sin_family = PF_INET; 18 sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 19 sockAddr.sin_port = htons(1234); 20 connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); 21 22 //接收服务器传回的数据 23 char szBuffer[MAXBYTE] = {0}; 24 recv(sock, szBuffer, MAXBYTE, NULL); 25 26 //输出接收到的数据 27 printf("Message form server: %s\n", szBuffer); 28 29 //关闭套接字 30 closesocket(sock); 31 32 //终止使用 DLL 33 WSACleanup(); 34 35 system("pause"); 36 return 0; 37 }
1) Windows 下的 socket 程序依赖 Winsock.dll 或 ws2_32.dll,必须提前加载。DLL 有两种加载方式
2) Linux 使用“文件描述符”的概念,而 Windows 使用“文件句柄”的概念;Linux 不区分 socket 文件和普通文件,而 Windows 区分;Linux 下 socket() 函数的返回值为 int 类型,而 Windows 下为 SOCKET 类型,也就是句柄。
3) Linux 下使用 read() / write() 函数读写,而 Windows 下使用 recv() / send() 函数发送和接收。
4) 关闭 socket 时,Linux 使用 close() 函数,而 Windows 使用 closesocket() 函数。
WinSock(Windows Socket)编程依赖于系统提供的动态链接库(DLL),有两个版本:
- 较早的DLL是 wsock32.dll,大小为 28KB,对应的头文件为 winsock1.h;
- 最新的DLL是 ws2_32.dll,大小为 69KB,对应的头文件为 winsock2.h。
使用DLL之前必须把DLL加载到当前程序,你可以在编译时加载
#pragma comment (lib, "ws2_32.lib")
,也可以在程序运行时加载