先看 效果截圖
在工具菜單下選擇編譯器選項
添加編譯命令-lwsock32 codeblock這些都是這樣的(不設置將會編譯失敗)
首先是初始化 使用Win Socket 必須初始化 原因是 系統有一個Socket池 需要使用Socket則在池中拿一個
具體解釋可以參考
http://blog.sina.com.cn/s/blog_4b146a9c01011ncl.html
在這一步客戶端和服務器都是一樣的
//初始化WSA
WORD sockVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData)!=0)
{
return 0;
}
之後就是分別介紹
服務器
服務器初始化SOCKECT
//創建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(slisten == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
使用socket函數進行初始化
這個函數有三個參數:
第一個參數:表示 協議域,又稱爲協議族
- AF_INET (IPV_4)
- AF_INET6 (IPV_6)
- AF_LOCAL(AF_UNIX,本地通信用)
- AF_ROUTE ( 路由套接字)
還有一些暫時不做介紹(太多了看不完 QAQ)
第二個參數:信息傳送方式
- SOCK_STREAM 有保障的(即能保證數據正確傳送到對方)面向連接的SOCKET
- SOCK_DGRAM 無保障的面向消息的socket
- SOCK_RAW 原始套接字(更接近底層的操作)端口對於SOCK_RAW而言沒有任何意義
關於SOCK_RAW具體參考https://www.cnblogs.com/aspirant/p/4084127.html、http://blog.chinaunix.net/uid-29426265-id-4217021.html
- SOCK_PACKET (Windows 下似乎是不支持的 這裏不做討論)
- SOCK_SEQPACKET (與網絡驅動程序直接通信)
- SOCK_RDM: 提供可靠的數據包連接 (Linux 下似乎不支持 ?)
SOCK_STREAM是基於TCP的,數據傳輸比較有保障。
SOCK_DGRAM是基於UDP的,專門用於局域網,基於廣播SOCK_STREAM 是數據流,一般是tcp/ip協議的編程,SOCK_DGRAM分是數據抱,是udp協議網絡編程
第三個參數 :對應協議
- IPPROTO_TCP TCP傳輸協議
- IPPROTO_UDP UDP傳輸協議
- IPPROTO_SCTP STCP傳輸協議
- IPPROTO_TIPCTIPC傳輸協議
- 庫裏面還有很多定義 有機會用用。。
現在已經得到了一個Socket描述符接下來開始使用它 連接服務器或者等待客戶端連接
首先我們看服務器等待客戶端連接
//綁定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET; //指定家族 (選擇IP 地址類型)
sin.sin_port = htons(8888); //指定端口號
sin.sin_addr.S_un.S_addr = INADDR_ANY;
//可以設置爲
// #define INADDR_ANY (u_long)0 //綁定地址0.0.0.0上的監聽, 能收到任意一塊網卡的連接;
// #define INADDR_LOOPBACK 0x7f000001 //綁定地址LOOPBAC, 往往是127.0.0.1, 只能收到127.0.0.1上面的連接請求
// #define INADDR_BROADCAST (u_long)0xffffffff //廣播地址
if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) //進行綁定
{
printf("bind error !");
}
//開始監聽
if(listen(slisten, 5) == SOCKET_ERROR) //這個5表示最大連接數
{
printf("listen error !");
return 0;
}
接下來就是 監聽等待用戶連接
//循環接收數據
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true)
{
printf("等待連接...\n");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
/* if(sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}*/
printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
//接收數據
int ret = recv(sClient, revData, 255, 0);
if(ret > 0)
{
revData[ret] = 0x00;
printf(revData);
puts(0);
}
//發送數據
char sendData[100];
puts("\n\n你現在可以向客戶端發送信息:");
gets(sendData);
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
這個服務器只能一次接受一個用戶的連接 加入多線程 實現多個用戶連接
這個demo存在bug但是能實現簡單的多用戶連接
#include <stdio.h>
#include <winsock2.h>
#include <malloc.h>
typedef struct ThreadNode
{
int index;
HANDLE ThreadId;
SOCKET Client;
struct ThreadNode * next;
ThreadNode()
{
index = 0;
this->next = NULL;
}
}hThread;
hThread *clientHeadNote ,*clientEndNote;
hThread * addClient()
{
hThread * ClientNote = new hThread();
return ClientNote;
}
DWORD WINAPI ThreadClient(LPVOID param)
{
if(clientEndNote == NULL)
{
printf("empty Link\n");
return 0;
}
char revData[255];
SOCKET sClient = clientEndNote->Client;
while(1)
{
//接收數據
int ret = recv(sClient, revData, 255, 0);
if(ret > 0)
{
revData[ret] = 0x00;
printf(revData);
puts(0);
}
}
closesocket(sClient);
}
int main(int argc, char* argv[])
{
//初始化WSA
WORD sockVersion = MAKEWORD(2,2);
WSADATA wsaData;
if(WSAStartup(sockVersion, &wsaData)!=0)
{
return 0;
}
clientEndNote =clientHeadNote = NULL;
//創建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(slisten == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
//綁定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET; //指定家族 (選擇IP 地址類型)
sin.sin_port = htons(8888); //指定端口號
sin.sin_addr.S_un.S_addr = INADDR_ANY;
//可以設置爲
// #define INADDR_ANY (u_long)0 //綁定地址0.0.0.0上的監聽, 能收到任意一塊網卡的連接;
// #define INADDR_LOOPBACK 0x7f000001 //綁定地址LOOPBAC, 往往是127.0.0.1, 只能收到127.0.0.1上面的連接請求
// #define INADDR_BROADCAST (u_long)0xffffffff //廣播地址
if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) //進行綁定
{
printf("bind error !");
}
//開始監聽
if(listen(slisten, 5) == SOCKET_ERROR)
{
printf("listen error !");
return 0;
}
//循環接收數據
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
while (true)
{
printf("等待連接...\n");
SOCKET sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if(sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("接受到一個連接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
if(clientHeadNote == NULL)
{
clientHeadNote = addClient();
clientEndNote = clientHeadNote;
}
clientEndNote->Client = sClient;
clientEndNote->ThreadId = CreateThread(NULL, 0, ThreadClient, NULL, 0, NULL);
}
hThread * p;
while(clientHeadNote)//釋放佔用的內存空間
{
CloseHandle(clientHeadNote->ThreadId);
p = clientHeadNote;
clientHeadNote = clientHeadNote->next;
delete p;
}
closesocket(slisten);
WSACleanup();
return 0;
}
客戶端和服務器基本一致
#include <WINSOCK2.H>
#include <STDIO.H>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD sockVersion = MAKEWORD(2,2);
WSADATA data;
if(WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sclient == INVALID_SOCKET)
{
printf("無效的 socket !");
return 0;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
// puts("請輸入對方的IP地址");
char loa[16] = "127.0.0.1";
serAddr.sin_addr.S_un.S_addr = inet_addr(loa);
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
printf("連接錯誤 !");
closesocket(sclient);
return 0;
}
puts("連接成功!!");
puts("你現在可以向服務器發送信息:");
while(1)
{
char sendData[100];
gets(sendData);
send(sclient, sendData, strlen(sendData), 0);
}
// char recData[255];
// int ret = recv(sclient, recData, 255, 0);
// if(ret > 0)
// {
// recData[ret] = 0x00;
// printf(recData);
// }
//
closesocket(sclient);
WSACleanup();
return 0;
}