编程环境:CodeBlocks + MinGW
1、服务器端
#include <stdio.h>
#include <string.h>
#include <winsock32.h> // 函数定义头文件,调用API
#pragma comment(lib,"wsk2_32.lib") // Windows socket API
int main()
{
// 初始化WSA
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2,2);
if(WSAStartup(sockVersion,&wsaData) != 0)
{
//不为0说明初始失败
return 0;
}
// 创建socket
SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
// AF_INET 地址描述
// SOCK_STREAM socket类型
// IPPROTO_TCP 协议类型
if(sock == INVALID_SOCKET)
{
// socket创建失败
return 0;
}
// 服务器需要绑定端口和IP
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
// INADDR_ANY等价于inet_addr("0.0.0.0");
// 表示绑定服务器端所有可用IP
if(bind(sock,(SOCKADDR *)&sin,sizeof(sin)) == SOCKET_ERROR)
{
return 0; // 绑定失败
}
// 开启监听
if(listen(sock,5) == SOCKET_ERROR)
{
// 等待连接队列为5
return 0;
}
// 接受连接
SOCKET sClient;
SOCKADDR_IN rAddr;
int len = sizeof(rAddr);
while(1)
{
sClient = accept(sock,(SOCKADDR *)&rAddr,&len);
// 注意&len不可以省略&符号,与bind和connect不同
if(sClient == INVALID_SOCKET)
{
continue; // 连接无效,进行下次等待
}
// 打印客户端IP信息
printf("Connection from : %s\n",inet_ntoa(rAddr));
// 接收数据
char revData[255];
int ret = recv(sClient,revData,255,0);
// sClient不是sock 0为默认 255为接收长度
if(recv > 0)
{
revData[ret] = '\0'; // 结束字符
printf(revData);
}
// 发送数据
char *d = "Hello client,i am server!";
send(sClient,d,strlen(d),0);
// 关闭连接
closesocket(sClient);
}
// 善后收尾
closesocket(sock);
WSACleanup();
return 0;
}
2、客户端
#incldue <stdio.h>
#include <string.h>
// 不可缺少
#include <winsock32.h>
#pragma comment(lib,"wsk2_32.lib")
int main()
{
// 初始WSA
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2,2);
if(WSAStartup(sockVersion,&wsaData) != 0)
{
return 0;
}
// 创建socket
SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP));
if(sock == INVALID_SOCKET)
{
return 0;
}
// 设置服务器端口和IP,注意和服务器端区分
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888); // 与服务器一致
sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// "127.0.0.1"与服务器绑定地址一致
if(connect(sock,(SOCKADDR *)&sin,sizeof(sin)) == SOCKET_ERROR)
{
return 0; // 连接失败
}
// 发送数据,服务器先接收所以客户端先发送
char *d = "Hello server,i am client!";
send(sock,d,strlen(d),0);
// 接收
char revData[255];
int ret = recv(sock,revData,255,0);
if(ret > 0)
{
revData[ret] = '\n';
printf(revData);
}
// 善后收尾
closesocket(sock);
WSACleanup();
return 0;
}
3、UDP通信协议
服务器端不再需要接受连接,直接接收发送数据。客户端类似。它们都需要将IPPROTO_TCP改成IPPROTO_UDP。将SOCK_STREAM改成SOCK_DGRAM。
SOCKADDR_IN sin;
int len = sizeof(sin);
while(1)
{
char revData[255];
int ret = recvfrom(sock,revData,255,0,(SOCKADDR *)&sin,&len); // 接收时&len与发送时不同
if(ret > 0)
{
revData[ret] = '\0';
printf("接受到一个连接:%s\n", inet_ntoa(remoteAddr.sin_addr));
printf(revData);
}
char *d = "hello client!";
sendto(sock,revData,strlen(d),0,(SOCKADDR *)&sin,sizeof(sin));
}
报类似 undefined reference to `inet_addr@4’错误参考:
http://www.android100.org/html/201501/28/105793.html
最后吐槽一下:C语言的函数好难记( ̄へ ̄)