winsocket <研究了一天的成果>
首先,这都是套路( ▼-▼ )
头文件 #include <WinSock.h>
#include <Winsock2.h> 用这个,这个是升级版
各个函数解释
1、WSAStartup:
初始化套接字环境,本函数必须是应用程序或DLL调用的第一个Windows Sockets函数.它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节.应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数.
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
实际用例
//begin 初始化网络环境 int err = WSAStartup(MAKEWORD(2, 2), &wsaData); if ( err != 0) { printf("WSAStartup failed with error: %d\n", err); return -1; }//end
2、WSACleanup:
清理套接字环境,和上面的WSAStartup相反,该函数是在程序不在对任何Windows Sockets函数调用后,用其来清理套接字环境的
int WSACleanup (void);
//begin socket 一个套接字 hTcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == hTcpSocket) { MJS_LOG_ERROR("socket failed with error: \n"); WSACleanup(); return -1 ; }//end
4、int listen(SOCKET s, int backlog);
将套接字置入监听模式并准备接受连接请求。其中,参数s是服务器端套接字,于指定正在等待连接的最大队列长度。如无错误发生,listen函数返回0,失败则返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
int ServePort=20000; char ServeIP[32]="192.168.1.200"; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(ServePort); addr.sin_addr.S_un.S_addr = inet_addr(ServeIP); //连接服务器 if (connect(hTcpSocket, (sockaddr*)&addr, sizeof(sockaddr)) == -1) { closesocket(hTcpSocket); printf("connect Tradesys failed with error%d,%s,%d: \n",ServePort,ServeIP,GetLastError()); WSACleanup(); return -1; } else { printf("connect Tradesys sucessed,%d,%s: \n",ServePort,ServeIP); }
若无错误发生,则connect()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。对阻塞套接口而言,若返回值为SOCKET_ERROR则应用程序调用WSAGetLsatError()。如果它指出错误代码为WSAEWOULDBLOCK,则您的应用程序可以:
失败时返回 -1/SOCKET_ERROR
sockfd:已建立连接的发送端套接字描述符(非监听描述符)
buf:应用要发送数据的缓存
len:实际要发送的数据长度
flags:一般设置为0。 flags可取的值有:0、MSG_DONTROUTE或MSG_OOB或这些标志的按位或运算。
表示从接收缓冲区拷贝数据。成功时,返回拷贝的字节数,失败返回-1。阻塞模式下,recv/recvfrom将会阻塞到缓冲区里至少有一个字节(TCP)/至少有一个完整的UDP数据报才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1,置错误码为EWOULDBLOCK。
hostent结构:
struct hostent { char *h_name; //*h_name 表示的是主机的规范名 char **h_aliases; //h_aliases 表示的是主机的别名 int h_addrtype; //地址类型AF_INET,还是AF_INET6 int h_length; //IP地址占字节数 char **h_addr_list; //IP地址列表 };
int **h_addr_lisst 表示的是主机的ip地址 注意 是以网络字节序存储的。
14、const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) ;
这个函数,是将类型为af的网络地址结构src,转换成主机序的字符串形式,存放在长度为cnt的字符串中。这个函数,其实就是返回指向dst的一个指针。如果函数调用错误,返回值是NULL。
参数in:一个表示Internet主机地址的结构。
返回值:若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NVLL。其中的数据应在下一个WINDOWS套接口调用前复制出来。
//将主机的unsigned long值转化为网络字节顺序(32位),使用函数htonl() //参数hostlong标识主机字节顺序的数字,函数返回一个网络字节顺序的数字 #include <winsock.h> #include <stdio.h> #pragma comment (lib,"ws2_32.lib") void main() { u_long a = 0x12345678; u_long b = htonl(a); printf("%u/n",a); printf("%x/n",a); printf("%u/n",b); printf("%x/n",b); }
21、u_long PASCAL FAR ntohl( u_long netlong);
将一个无符号长整形数从网络字节顺序转换为主机字节顺序。
参数netlong:一个以网络字节顺序表达的32位数。
返回值:ntohl()返回一个以主机字节顺序表达的数。
//将32位网络字节转换为主机字节,使用函数ntohl() //定义如下 u_long ntohl(u_long netlong); #include <WINSOCK2.H> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") void main() { u_long a = 0x12345678; u_long b = ntohl(a); printf("%u/n",a); printf("%x/n",a); printf("%u/n",b); printf("%x/n",b); }
PS:
INADDR_ANY 就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。
以下是我写的代码
server:
#include <Winsock2.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> using namespace std; #pragma comment(lib,"ws2_32.lib") #define PORT 8888 int main() { //begin 初始化网络环境 WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){ //加载winsock2库 printf("加载失败./n"); return -1; } //end 初始化网络环境 struct sockaddr_in servaddr; //服务器端地址 memset(&servaddr, 0,sizeof(servaddr)); servaddr.sin_family = AF_INET; //填写要连接的服务器地址信息 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr()将命令行中输入的点分IP地址转换为二进制表示的网络字节序IP地址 servaddr.sin_port = htons(PORT); SOCKET socks = socket(AF_INET,SOCK_STREAM,0); //建立客户端流式套接口 if(socks == INVALID_SOCKET){ printf("建立接口失败/n"); return -1; } bind(socks,(struct sockaddr *)&servaddr,sizeof(servaddr)); //与服务器端建立连接 listen(socks, 10); //将套接字置入监听模式并准备接受连接请求,请求10是连接队列的最大长度 printf("正在连接......\n"); struct sockaddr_in addrClient; int addrClient_len = sizeof(addrClient); while (1) { SOCKET sockc = accept(socks, (struct sockaddr *)&addrClient, &addrClient_len); //建立套接字用于通信 char sen[100] = {0}; sprintf(sen,"%s", inet_ntoa(addrClient.sin_addr)); // 将客户端的IP地址存入c数组中 send(sockc, sen, strlen(sen) + 1, 0); // 发送数据到客户端 char receive[100] = {0}; recv(sockc, receive, 100, 0); // 接收客户端数据 printf("%s\n", receive); closesocket(sockc); } closesocket(socks); system("pause"); return 0; }
client:
#include <Winsock2.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> using namespace std; #pragma comment(lib,"ws2_32.lib") #define PORT 8888 int main() { //begin 初始化网络环境 WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0){ //加载winsock2库 printf("加载失败/n"); return -1; } //end 初始化网络环境 struct sockaddr_in addrSrv; addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(PORT); addrSrv.sin_addr.s_addr = inet_addr("10.22.26.126"); //要连接的服务器的ip地址 SOCKET sockc = socket(AF_INET,SOCK_STREAM,0); //建立客户端流式套接口 connect(sockc,(struct sockaddr *)&addrSrv,sizeof(addrSrv)); //与服务器进行连接 char receive[250] = {0}; recv(sockc, receive, 250, 0); // 接收客户端数据 printf("%s\n", receive); send(sockc, "hello world", strlen("hello world") + 1, 0); closesocket(sockc); system("pause"); return 0; }
分别建两个项目,然后打开各自的exe即可