使用Socket 創建 TCP、UDP 通信(Windows)

Socket的使用可以分爲TCP方式、UDP方式,下面就對兩種使用方式進行簡單的總結

1、TCP方式

TCP方式即點對點的方式,需要建立連接之後才能進行Socket通信。

服務器端:

在建立服務器端的Socket時,服務其端需要進行:

1、初始化SOCKET運行庫;

2、配置通信地址;

3、創建(socket)SOCKET;

4、綁定(bind)SOCKET地址;

5、監聽(listen)SOCKET地址;

6、接受(accept)SOCKET的連接;

具體實例如下:

//發送端

char name[80];
hostent* pHost;
gethostname(name,sizeof(name));//獲取本機主機名
pHost = gethostbyname(name);
ip = inet_ntoa(*(struct in_addr*)pHost->h_addr_list[0]);//獲取本機IP

int err;

WSADATA wsaData;
WORD wVersion;
wVersion = MAKEWORD(2,2);//生成加載的Winsock庫的版本
err = WSAStartup(wVersion,&wsaData);//加載套接字庫

if(err != 0){return;}

SOCKADDR_IN local_addr;
int addrsize = sizeof(SOCKADDR_IN);

local_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(5150);//綁定端口

if((listen_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{ //創建SOCKET失敗   }
else
{      //創建SOCKET成功    }

if(bind(listen_sock,(struct sockaddr*)&local_addr,addrsize))
{//綁定SOCKET失敗   }
else
{//綁定SOCKET失敗   }

listen(listen_sock,1);//20160426 監聽一個客戶端



SOCKADDR_IN client_addr;//存儲連接的客戶端地址

SOCKET Client_Sock;//存儲連接的客戶端SOCKET

if((Client_Sock=accept(listen_sock,(struct sockaddr*)&client_addr,&addrsize))==INVALID_SOCKET)
{//服務器accept失敗   }
else{
{ //服務器accept成功   
//port.Format("%d",int(ntohs(client_addr.sin_port)));
//("已連接來自:"+CString(inet_ntoa(client_addr.sin_addr))+"端口:"+port);
}

//接收數據

char recvMsg[1024] = {0};

int rs = -10;

rs = recv(Client_sock, recvMsg, 1024, 0);

if(rs==-1 || rs==0){//接收數據錯誤}

else{recvMsg[rs] = ‘\0’}

//發送數據

if(send(Client_sock, sendMsg, strlen(sendMsg),0)==SOCKET_ERROR)
{
    //發送失敗
}

客戶端:

 

在建立客戶端的Socket時,服務其端需要進行:

1、初始化SOCKET運行庫;

2、配置通信地址;

3、創建(socket)SOCKET;

4、連接(connect)服務器端的地址;

 

具體實例如下:

WSADATA wsaData;
SOCKADDR_IN server_addr;
WORD wVersion;

wVersion = MAKEWORD(2,2);
WSAStartup(wVersion,&wsaData);

server_addr.sin_addr.S_un.S_addr = inet_addr(ip);//服務端IP
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);//服務端綁定的端口

if((sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{
printf("Error:創建SOCKET失敗!\r\n");
}
else if(connect(sock,(struct sockaddr*)&server_addr,sizeof(SOCKADDR_IN))==SOCKET_ERROR)
{
printf("Error:連接服務器失敗!\r\n");
}
else
{
printf(">成功連接服務器!\r\n");
}

//接收數據

char recvMsg[1024] = {0};

int rs = -10;

rs = recv(sock, recvMsg, 1024, 0);

if(rs==-1 || rs==0){//接收數據錯誤}

else{recvMsg[rs] = ‘\0’}

//發送數據

if(send(sock, sendMsg, strlen(sendMsg),0)==SOCKET_ERROR)
{
    //發送失敗
}

2、UDP方式

UDP的通訊方式不需要提前建立連接即可發送、接收數據。當需要數據傳輸時,只需要向某地址發送數據即可,

當接收方發現接收緩存區中有數據時,就會把數據讀取出來。這種模式數據傳輸比較快,但可靠型略低,可能會造成丟包。

當採用UDP方式時,並沒有嚴格的服務器、客戶端之分;爲了方便理解,可以理解爲發送方、接收方。

 

服務器端:

在建立服務器端的Socket時,服務其端需要進行:

1、初始化SOCKET運行庫;

2、配置通信地址;

3、創建(socket)SOCKET;

4、發送數據(sendto);

具體實例如下:

WSADATA wsaData;
WORD wVersion;

wVersion = MAKEWORD(2,2);
if(WSAStartup(wVersion,&wsaData) != 0)
{
    UpdateStatus("初始化SOCKET失敗!");
    exit(1);
}

SOCKET SockUdp;
SOCKADDR_IN serverAddr;
int addrsize = sizeof(SOCKADDR_IN);

if((SockUdp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
{
    UpdateStatus("創建UDP-SOCKET失敗!");
    return;
}

//for send
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.S_un.S_addr = inet_addr("接收端IP地址");
serverAddr.sin_port = htons(9000);    // 接收端端口號

//發送數據

int fromlength=sizeof(serverAddr);
sendto(SockUdp, sendMsg, strlen(sendMsg), 0, (struct sockaddr FAR *)&serverAddr, fromlength);

客戶端:

在建立客戶端的Socket時,服務其端需要進行:

1、初始化SOCKET運行庫;

2、配置通信地址;

3、創建(socket)SOCKET;

4、綁定(bind)接收地址;

5、接收數據(recvFrom)

 

具體實例如下:

WSADATA wsaData;
WORD wVersion = MAKEWORD(2,2);
WSAStartup(wVersion,&wsaData);

SOCKET sock;
SOCKADDR_IN recvAddr;    // 接收端(客戶端)的地址
SOCKADDR_IN sendAddr;    // 發送端(服務端)的地址,只用於存儲

if((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==INVALID_SOCKET)
{
    printf("》創建 UDP SOCKET 失敗!\r\n");
}
 
int nlen=sizeof(SOCKADDR_IN); 

//用來從網絡上的廣播地址接收消息
recvAddr.sin_family = AF_INET;
recvAddr.sin_addr.S_un.S_addr = inet_addr("本機接收IP地址");//接收數據端可以以這種方式設置
recvAddr.sin_port = htons(9000); // 本機接收數據的端口號

//bind
if (bind(sock, (SOCKADDR*)&recvAddr, sizeof(recvAddr)) != 0)  
{   
    printf("》bind error:%d\n", err);  
    closesocket(sock);  
    WSACleanup(); 
}

//接收數據

int res = -10;

int addr_len=sizeof(SOCKADDR_IN);

char recvMsg[1024] = {0};

res = recvfrom(sock, recvMsg,1024, 0, (struct sockaddr *)&sendAddr, &addr_len);
if( res == SOCKET_ERROR)
{ 
    UpdateStatus("》未正確接收數據!");
    int err = WSAGetLastError(); 
    break;
}
else if(res > 0)
{//數據接收成功

    //recvMsg[res] = ‘\0’;

}

 

3、備註

無論採取什麼方式,都必須包含頭文件: Winsock2.h

同時需要加載ws2_32.lib文件:#pragma comment(lib, "ws2_32.lib")

 

在創建SOCKET時。TCP方式的第二個參數爲SOCK_STREAM,UDP方式的第二個參數爲SOCK_DGRAM.

TCP方式下,在服務器端需要綁定地址,而對於UDP方式來說,只要接收數據,就需要綁定接收地址

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章