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);

 

3、SOCKET socket(int af, int type, int protocol);
建立套接字 參數af用於指定網絡地址類型,一般取AF_INET,表示該套接字在Internet域中,進行通信。 參數type用於知道套接字的類型,若取SOCK_STREAM表示創建的套接字是流套接字,而取SOCK_DGRAM創建數字報套接字。 參數protocol用於指定網絡協議,一般取0,表示默認為TCP/IP協議。 若套接字創建成功則該函數返回創建的套接字句柄SOCKET,否則產生INVALID_SOCKET錯誤。
實際用例
//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()獲取相應錯誤代碼。

 
5、SOCKET accept( SOCKET s, struct sockaddr* addr, int* addrlen );
參數s同上,addr是一個有效的SOCKADDR_IN結構的地址,而addrlen是sockaddr_in結果的長度。accept函數返回后,addr參數變量中會包含發出連接請求的那個客戶機的IP地址信息,而addrlen參數則指出該結構的長度,並返回一個新的套接字描述符,它對應於已經接受的那個客戶機連接。

 

6、 int bind( SOCKET s, const struct sockaddr* name, int namlen );
綁定到本地,name中指定的IP應該是當前運行該程序機器的IP。
 

 

7、int connect( SOCKET s, const struct sockaddr FAR* name, int namelen );
連接到服務器
實際用例
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.用select(),通過檢查套接口是否可寫,來確定連接請求是否完成。或者,
2.如果您的應用程序使用基於消息的WSAAsynSelect()來表示對連接事件的興趣,則當連接操作完成后,您會收到一個FD_CONNECT消息。
 
8、 int send( SOCKET s, const char* buf, int len, int flags );

失敗時返回 -1/SOCKET_ERROR

       sockfd:已建立連接的發送端套接字描述符(非監聽描述符)

       buf:應用要發送數據的緩存

       len:實際要發送的數據長度

       flags:一般設置為0。  flags可取的值有:0、MSG_DONTROUTE或MSG_OOB或這些標志的按位或運算。

 

9、int recv( SOCKET s, char* buf, int len, int flags );
s是准備接收數據的套接字,buf是即將收到數據的字符緩沖區,而len則是准備接受的字節數或buf緩沖的長度。flags一般指定為0.參數可以是0、MSG_PEEK或MSG_OOB或這些標志的按位“或”運算。

 表示從接收緩沖區拷貝數據。成功時,返回拷貝的字節數,失敗返回-1。阻塞模式下,recv/recvfrom將會阻塞到緩沖區里至少有一個字節(TCP)/至少有一個完整的UDP數據報才返回,沒有數據時處於休眠狀態。若非阻塞,則立即返回,有數據則返回拷貝的數據大小,否則返回錯誤-1,置錯誤碼為EWOULDBLOCK。

 

10、int shutdown( SOCKET s, int how );
其中,how參數用於描述禁止哪些操作,它可取的值有:SD_RECEIVE、SD_SEND或SD_BOTH。 如果是SD_RECEIVE,就表示不允許再調用接收函數, 如果選擇SD_SEND,表示不允許再調用發送函數, 如果是SD_BOTH, 則表示取消連接兩端的收發操作。 如果沒有錯誤發生,shutdown()返回0,否則返回SOCKET_ERROR錯誤。
 
11、 int closesocket(SOCKET s );
s是要關閉的套接字描述字,再利用套接字執行調用就會失敗。
 
12 int gethostname(char *name, size_t len):
這個函數,調用后,會將主機名保存在name里面。而len是name的大小。該函數返回0表示成功,否則失敗。
 
13、struct hostent *gethostbyname(const char *name);
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。

 

15、struct hostent FAR *PASCAL FAR gethostbyaddr(const char FAR * addr, int len, int type);
參數addr:指向網絡字節順序地址的指針。 參數len: 地址的長度,在PF_INET類型地址中為4。 參數type:指地址類型AF_INET、IF_INET6

 

16、inet_ntoa( char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
將網絡地址轉換成“.”點隔的字符串格式。本函數將一個用in參數所表示的Internet地址結構轉換成以“.” 間隔的諸如“a.b.c.d”的字符串形式。請注意inet_ntoa()返回的字符串存放在WINDOWS套接口實現所分配的內存中。應用程序不應假設該內存是如何分配的。在同一個線程的下一個WINDOWS套接口調用前,數據將保證是有效。

參數in:一個表示Internet主機地址的結構。

返回值:若無錯誤發生,inet_ntoa()返回一個字符指針。否則的話,返回NVLL。其中的數據應在下一個WINDOWS套接口調用前復制出來。

 

17、unsigned long inet_addr(  const char   FAR *cp);
將點格式的IP地址轉換為無符號類型存儲。
 
18、u_short PASCAL FAR htons( u_short hostshort);
作用是將主機的無符號短整形數轉換成網絡字節順序。
 
19、 u_short PASCAL FAR ntohs( u_short netshort);
 
20、u_long PASCAL FAR htonl( u_long hostlong);
本函數將一個32位數從主機字節順序轉換成網絡字節順序。
實際用例
//將主機的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:

錯誤代碼:
WSANOTINITIALISED:在使用此API之前應首先成功地調用WSAStartup()。
WSAENETDOWN:WINDOWS套接口實現檢測到網絡子系統失效。
WSAEINVAL:超時時間值非法。
WSAEINTR:通過一個WSACancelBlockingCall()來取消一個(阻塞的)調用。
WSAEINPROGRESS:一個阻塞的WINDOWS套接口調用正在運行中。
WSAENOTSOCK:描述字集合中包含有非套接口的元素。
WSAEADDRINUSE:所指的地址已在使用中。
WSAEADDRNOTAVAIL:在本地機器上找不到所指的地址。
WSAENOTSUPPORT:所指族中地址無法與本套接口一起使用。
WSAECONNREFUSED:連接嘗試被強制拒絕。
WSAEDESTADDREQ:需要目的地址。
WSAEFAULT:namelen參數不正確。
WSAEINVAL:套接口沒有准備好與一地址捆綁。
WSAEISCONN:套接口早已連接。
WSAEMFILE:無多余文件描述字。
WSAENETUNREACH:當前無法從本主機訪問網絡。
WSAENOBUFS:無可用緩沖區。套接口未被連接。
WSAENOTSOCK:描述字不是一個套接口。
WSAETIMEOUT:超時時間到。
WSAEWOULDBLOCK:套接口設置為非阻塞方式且連接不能立即建立。可用select()調用對套接口寫,因為select()時會進行連接。
 
 
 
 

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即可

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM