閱讀122 返回首頁    go 阿裏雲 go 技術社區[雲棲]


socket編程(1)簡單的TCP/UDP編程

socket編程是一種與底層網絡協議無關的編程方式,socket意味一種插口,即一個地址配上一個端口就構成了一端插口,既然他與底層協議無關,所以我們在使用socket 編程的時候,就可以任意選用哪種網絡協議,如最流行的tcp/ip協議。

在所有socket編程前腰包含頭文件<WinSock2.h>

服務器端:服務器端是指在tcp中進行監聽,也就是被動連接的那一端,服務器端在於客戶端建立好連接後,可以同服務器端發送和接收信息,他用一個監聽socket進行監聽客戶端連接,然後得到連接後可以創建一個通信socket進行通信,可以同時與多個客戶端通信,服務器端的編程主要有以下幾步:

1.初始winsocket

WSAStartup(MAKEWORD(2,2),&wsad);

2.建立一個用於監聽的socket
    listenSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);

3.設定監聽socket的地址端口,並綁定給這個socket

    listenAddr.sin_family=AF_INET;
    listenAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    listenAddr.sin_port=htons(11111);

    if(bind(listenSocket,(SOCKADDR *)(&listenAddr),sizeof(listenAddr))==SOCKET_ERROR){
        abort();
        return;
    }

4.進行監聽  

if(listen(listenSocket,1)==SOCKET_ERROR){
        abort();
    }

5.循環等待新連接進入的socket,如果等到則創建一個socket與之通信,accept操作是一個阻塞的操作。

    while(!stopped){
        acceptSocket=WSAAccept(listenSocket,(SOCKADDR*)(&clientAddr),&clientAddrSize,0,0);
        if(acceptSocket==INVALID_SOCKET){
            int code=WSAGetLastError();
            break;
        }

//這裏可以得到接入的socket的地址端口
        char* add=inet_ntoa(clientAddr.sin_addr);
        int port=ntohs(clientAddr.sin_port);
//   acceptSocket就是一個已經於客戶端連接上的可以進行通信的socket,這裏 要 啟用一個 新線程用acceptSocket閾值通信

}

}

6、在啟用的新線程中一般是這樣的:

調用recv或send函數接收和發送信息

   ret=recv(acceptSocket,buf,1000,0);

在線程結束前要關閉這個socket
  closesocket(acceptSocket);

7關閉服務器

首先關閉監聽的socket

closesocket(listenSocket);

然後清理winsocket
WSACleanup();

**************************************************************************************

客戶端:客戶端socket是進行主動連接的那一方,客戶端的編程通常是這樣的:

1.初始winsocket

WSAStartup(MAKEWORD(2,2),&wsad);

2.建立一個用於連接的socket


    csocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);

3.設定監聽socket的地址端口,並綁定給這個socket

    caddres.sin_family=AF_INET;
    caddres.sin_addr.s_addr=inet_addr("127.0.0.1");
    caddres.sin_port=htons(11111);

4、想某個服務器發送連接
    if(WSAConnect(csocket,(SOCKADDR*)(&caddres),sizeof(caddres),0,0,0,0)==SOCKET_ERROR){
        abort();
        return;
    }

5調用recv或send函數接收和發送信息

6通信結束後關閉

closesocket();
   WSACleanup();

************************************************************************************

send和recv的一些方法:

send()函數不保證會把send的內容全部send出去,這樣就可能要多次send(),常用的方法是

int totalbyte=data.size();
    DWORD ret;
    WSABUF sendBuf;
    sendBuf.len=totalbyte;
    sendBuf.buf=data;
    while(totalbyte>0){
        if(WSASend(csocket,&sendBuf,1,&ret,0,0,0)==SOCKET_ERROR){
            abort();
            return;
        }
        totalbyte-=ret;
        sendBuf.len=totalbyte;
        sendBuf.buf+=ret;
    }

*******************************************************************************************

下麵是基於無連接的UDP編程方法

這使用的是無連接的協議,TCP是有連接的,即要求在連接之前需要服務器端和客戶端都綁定端口,然後連接後可以雙向發送接收。

但是無連接的協議隻需要服務器端綁定端口,而客戶端不需要,客戶端隻需要向服務器端的監聽端口發送消息就可以了,也隻能由客戶端向服務器端發送消息。程序的實現如下;

服務器端

1.初始化

WSAStartup(MAKEWORD(2,2),&wsad);

2.創建用於監聽的socket
    s=socket(AF_INET,SOCK_DGRAM,0);

3.綁定一個地址端口
    SOCKADDR_IN udpAdress,sender;
    int senferAddSize=sizeof(sender);
    udpAdress.sin_family=AF_INET;
    udpAdress.sin_port=htons(11112);
    udpAdress.sin_addr.s_addr=inet_addr("127.0.0.1");
    bind(s,(SOCKADDR*)&udpAdress,sizeof(udpAdress));

4.就可以調用recvfrom這個無連接的的接收函數接收數據,這個函數是阻塞的。無連接的協議不保證數據傳輸的可靠性,而且一次傳輸的數據量是有限的
    ret=recvfrom(s,data,1000,0,(SOCKADDR*)&sender,&senferAddSize);

5.結束後關閉socket和清理

客戶端

1.初始化

WSAStartup(MAKEWORD(2,2),&wsad);

2.創建一個socket,但是不用綁定端口
    usocket=socket(AF_INET,SOCK_DGRAM,0);

3.使用無連接的發送函數sendto向指定地址發送數據
      sendto(usocket,data(),totalbyte,0,(SOCKADDR*)&dstAdd,dstAddrSize);

4.關閉、清理
    closesocket(usocket);
    WSACleanup();

最後更新:2017-04-02 06:51:36

  上一篇:go Javascript:控製Li選中項樣式
  下一篇:go socket編程(3)廣播 多播