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方式來說,只要接收數據,就需要綁定接收地址