在工具菜单下选择编译器选项
添加编译命令-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协议网络编程
第三个参数 :对应协议
现在已经得到了一个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
#include
#include
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
#include
#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;
}