在Windows7系统下,采用工具为VC++,Win32控制台应用程序,编写一个基于TCP的Client/Server网络程序。
1、服务器端代码
#include <WinSock2.h>
#include <stdio.h>
#define SERVERPORT 6000 //服务端口号
int main(int argc, char *argv[])
{
//加载套接字库
WORD wVersionRequested;//用于保存WinSock库的版本号
WSADATA wsaData;
int err;
printf("This is a Server side application!\n");
wVersionRequested = MAKEWORD(2,2);
err = WSAStartup( wVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup() called failed!\n");
return -1;
}
else
{
printf("WSAStartup() called successful!\n");
}
if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2)
{
//若不是所请求的版本号2.2,则终止WinSock库的使用
WSACleanup();
return -1;
}
//创建用于监听的套接字
SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
if(sockServer == INVALID_SOCKET)
{
printf("socket() called failed! ,error code is: %d", WSAGetLastError());
return -1;
}
else
{
printf("socket() called successful!\n");
}
//填充服务器端套接字结构
SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//将主机字节顺序转换成TCP/IP网络字节顺序
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT);
//将套接字绑定到一个本地地址和端口上
err = bind(sockServer, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
if (err == SOCKET_ERROR)
{
printf("bind() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("bind() called successful\n");
}
//将套接字设置为监听模式,准备接收客户请求
err = listen(sockServer, 5);
if (err == SOCKET_ERROR)
{
printf("listen() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("listen() called successful!\n");
}
SOCKADDR_IN addrClient; //保存发送请求连接的客户端的套接字信息
int len = sizeof(SOCKADDR);
while(1)
{
//等待客户请求到来
SOCKET sockConn = accept(sockServer, (SOCKADDR*)&addrClient, &len);
if (sockConn == INVALID_SOCKET)
{
printf("accept() called falied! The error code is: %d\n", WSAGetLastError());
}
else
{
printf("The Server receive a new client connection!\n");
}
char sendBuf[100];
sprintf_s(sendBuf, 100, "Welcome %s",inet_ntoa(addrClient.sin_addr));
//发送数据
send(sockConn, sendBuf, strlen(sendBuf)+1 , 0);
char recvBuf[100];
//接收数据
recv(sockConn, recvBuf, 100, 0);
//打印接收到的数据
printf("receive data from client side [%s,%d] is: %s\n", inet_ntoa(addrClient.sin_addr), addrClient.sin_port,
recvBuf);
closesocket(sockConn); //关闭连接套接字
}
return 0;
}
2、客户端代码
#include <WinSock2.h>
#include <stdio.h>
#define SERVERPORT 6000 //服务端口号
#pragma comment(lib, "WS2_32.lib");
int main(int argc, char *argv[])
{
//加载套接字库
WORD wVersionRequested;
WSAData wsaData;
int err;
printf("This is a Client side application!\n");
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0 )
{
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("WSAStartup() called failed!\n");
return -1;
}
else
{
printf("WSAStartup() called successful!\n");
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
WSACleanup( );
return -1;
}
/* The WinSock DLL is acceptable. Proceed. */
//创建套接字
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
if(sockClient == INVALID_SOCKET)
{
printf("socket() called failed! ,error code is: %d", WSAGetLastError());
return -1;
}
else
{
printf("socket() called successful!\n");
}
//需要连接的服务端套接字结构信息
SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//设定服务器的IP地址
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT);//设定服务器的端口号(使用网络字节序)
//向服务器发出连接请求
err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
if (err == SOCKET_ERROR)
{
printf("connect() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("connect() called successful\n");
}
//接收数据
char recvBuf[100]={0};
recv(sockClient, recvBuf, 100, 0);
printf("receive data from server side is: %s\n", recvBuf);
//发送数据
send(sockClient, "This is a client side!\n", strlen("This is a client side!\n")+1, 0);
//关闭套接字
closesocket(sockClient);
//终止套接字库的使用
WSACleanup();
return 0;
}
另外,需要注意的是需要在服务器和客户端都需要链接WinSock静态链接库Ws2_32.lib,有两种添加方法
方法一:在工程配置属性中添加
假如创建一个名为TCPClient的Win32控制台应用程序
在VS2017中添加静态链接库WS2_32.lib的方法如下:
(1)切换到TCPServer的【Solution Explorer】,选择菜单【Project】->【TCPClient Properties】
(2)在TCPClient Properties Pages对话框中,依次选择【Configuration Properties】->【Linker】->【Input】,在右侧的【Addtional Dependencies】中添加Ws2_32.lib库。
如下如所示:
服务器TCPServer也需要链接Ws2_32.lib库,方法和客户端TCPClient一样。
程序结果运行如下:
先启动服务器端程序TCPServer,结果如下:
[图片上传中...(image-434fe9-1601013270130-7)]
[图片上传中...(image-ee4558-1601013270129-2)]
再启动客户端TCPClient,客户端结果如下:
[图片上传中...(image-c6f83d-1601013270130-6)]
[图片上传中...(image-c0f11d-1601013270129-1)]
服务器端TCPServer结果如下:
[图片上传中...(image-44e9e1-1601013270129-0)]
方法二:在代码中添加
#pragma comment(lib, "WS2_32.lib");
参考资料:
1、《VC++深入详解》 第14章网络编程 ,孙鑫主编
2、MSDN帮助文档