首先,這都是套路( ▼-▼ )
頭文件 #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即可