实验目的:
学习SOCKET编程基础,掌握Winsock主要库函数
实验效果:
- 客户和服务器之间都可以在键盘上输入语句并且发送给对方,并且都可以接收对方发送来的语句,并且在显示器上显示。
- 显示服务器端的点分十进制IP地址,long 型IP地址,short型IP地址和Char型IP地址。
- 服务器显示客户端点分十进制IP地址,客户端显示服务器点分十进制IP地址
特别说明
我的实验设备:Microsoft Visual Studio 2013(不同的工具某些函数会略有不同,但是英语只要四级过了,主要看报错提示都能解决,其中6.0版本头文件不能有#include “stdafx.h”)
各位梭友自行更改ip地址哟,以后就霸道得默认你们都知道。(方法是win+r输入ipconfig/all)
第一部分运行结果显示:
流程图:
流程图是有那么一套明确并且通用的规范,希望各位小伙伴及早学习。什么叫做流程图?如何制作规范的流程图?
客户端代码:
// 大作业客户端.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Winsock2.H>
#include <string>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 65535 // 缓冲区大小
int main(int argc, CHAR* argv[])
{
WSADATA wsd; // 用于初始化Windows Socket
SOCKET sHost; // 与服务器进行通信的套接字
SOCKADDR_IN servAddr; // 服务器地址
//SOCKET sServer; // 服务器套接字,用于监听客户端请求
//SOCKET sClient; // 客户端套接字,用于实现与客户端的通信
char buf[BUF_SIZE]; // 用于接受数据缓冲区
int retVal; // 调用各种Socket函数的返回值
// 初始化Windows Socket
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
printf("WSAStartup failed!\n");
return -1;
}
// 创建套接字
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost){
printf("socket failed!\n");
WSACleanup();
return -1;
}
// 设置服务器地址
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.43.62"); // 用户需要根据实际情况修改
servAddr.sin_port = htons(9990); // 在实际应用中,建议将服务器的IP地址和端口号保存在配置文件中
int sServerAddlen = sizeof(servAddr); // 计算地址的长度
// 连接服务器
retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));
if (retVal == SOCKET_ERROR){
printf("connect failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
}
// 循环向服务器发送字符串,并显示反馈信息。
// 发送quit将使服务器程序退出,同时客户端程序自身也将退出
int count = 1;
while (count<10)
{
// 向服务器发送数据
printf("Please input a string to send: ");
// 接收输入的数据
std::string str;
std::getline(std::cin, str);
getchar();
// 将用户输入的数据复制到buf中
ZeroMemory(buf, BUF_SIZE);
strcpy_s(buf, str.c_str());
// 向服务器发送数据
retVal = send(sHost, buf, strlen(buf), 0);
if (SOCKET_ERROR == retVal)
{
printf("send failed !\n");
closesocket(sHost);
WSACleanup();
return -1;
}
ZeroMemory(buf, BUF_SIZE);// 清空接收数据的缓冲区
// 接收服务器回传的数据
retVal = recv(sHost, buf, BUFSIZ, 0);
printf("Message aply : %s\n", buf);
printf("---------第 %d 次对话结束-----------\n", count);
count++;
}
// 释放资源
closesocket(sHost);
WSACleanup();
// 暂停,按任意键继续
system("pause");
return 0;
}
服务器代码:
// 大作业服务器端.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <WINSOCK2.H>
#include <string>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 65535 // 缓冲区大小
int main(int argc, CHAR* argv[])
{
WSADATA wsd; // WSADATA变量,用于初始化Windows Socket
SOCKET sServer; // 服务器套接字,用于监听客户端请求
SOCKET sClient; // 客户端套接字,用于实现与客户端的通信
int retVal; // 调用各种Socket函数的返回值
char buf[BUF_SIZE]; // 用于接受客户端数据的缓冲区
// 初始化套接字动态库
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
printf("WSAStartup failed!\n");
return -1;
}
// 创建用于监听的套接字
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sServer){
printf("socket failed!\n");
WSACleanup();
return -1;
}
// 设置服务器套接字地址
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(9990); // 监听端口为9990
//addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrServ.sin_addr.S_un.S_addr = inet_addr("192.168.43.62");
// 绑定套接字sServer到本地地址,端口9990
retVal = bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));
if (retVal == SOCKET_ERROR){
printf("bind failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 监听套接字
retVal = listen(sServer, 1);
if (retVal == SOCKET_ERROR){
printf("listen failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 接受客户请求
printf("TCP Server start...!\n");
SOCKADDR_IN addrClient;//客户端地址
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);
if (sClient == INVALID_SOCKET){
printf("accept failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 循环接收客户端的数据,直接客户端发送了10次数据后退出。
int count = 1;
while (count<10)
{
ZeroMemory(buf, BUF_SIZE); // 清空接收数据的缓冲区
//接收数据
retVal = recv(sClient, buf, BUFSIZ, 0);
if (retVal == SOCKET_ERROR){
printf("recv failed!\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
// 获取当前系统时间
SYSTEMTIME st;
GetLocalTime(&st);
char sDateTime[30];
sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
// 打印输出的信息
printf("%s, Recv From Client [%s:%d] :%s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf);
//向客户端发送回复消息
printf("Please input a string to send to client: ");
// 接收输入的数据
std::string str;
std::getline(std::cin, str);
getchar();
// 将用户输入的数据复制到buf中
ZeroMemory(buf, BUF_SIZE);
strcpy_s(buf, str.c_str());
// 向服务器发送数据
char msg[BUF_SIZE];
sprintf_s(msg, " %s", buf);
retVal = send(sClient, msg, strlen(msg), 0);
if (SOCKET_ERROR == retVal)
{
printf("send failed !\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
printf("---------第 %d 次对话结束-----------\n", count);
count++;
}
//服务器退出 释放套接字
closesocket(sServer);
closesocket(sClient);
WSACleanup();
// 暂停,按任意键退出
system("pause");
return 0;
}
第二和三部分运行效果(只需要理解代码中的“增加部分就行”):
// 大作业服务器端.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <WINSOCK2.H>
#include <string>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 65535 // 缓冲区大小
int main(int argc, CHAR* argv[])
{
WSADATA wsd; // WSADATA变量,用于初始化Windows Socket
SOCKET sServer; // 服务器套接字,用于监听客户端请求
SOCKET sClient; // 客户端套接字,用于实现与客户端的通信
int retVal; // 调用各种Socket函数的返回值
char buf[BUF_SIZE]; // 用于接受客户端数据的缓冲区
// 初始化套接字动态库
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
printf("WSAStartup failed!\n");
return -1;
}
// 创建用于监听的套接字
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sServer){
printf("socket failed!\n");
WSACleanup();
return -1;
}
// 设置服务器套接字地址
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(9990); // 监听端口为9990
//addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrServ.sin_addr.S_un.S_addr = inet_addr("192.168.43.62");
// 绑定套接字sServer到本地地址,端口9990
retVal = bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));
if (retVal == SOCKET_ERROR){
printf("bind failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
//———————————————————————————增加内容———————————
printf("显示服务器端的点分十进制IP地址,long 型IP地址,short型IP地址和Char型IP地址:\n");
printf("服务器IP地址:%s \r\n", inet_ntoa(addrServ.sin_addr));
printf_s("服务器(long型)IP地址:%ld \r\n", addrServ.sin_addr.S_un.S_addr);
printf_s("服务器(short型)IP地址:%d %d\r\n", addrServ.sin_addr.S_un.S_un_w.s_w1, addrServ.sin_addr.S_un.S_un_w.s_w2);
printf_s("服务器(char型)IP地址:%d %d %d %d\r\n", addrServ.sin_addr.S_un.S_un_b.s_b1, addrServ.sin_addr.S_un.S_un_b.s_b2, addrServ.sin_addr.S_un.S_un_b.s_b3, addrServ.sin_addr.S_un.S_un_b.s_b4);
//——————————————————————————————————————————
// 监听套接字
retVal = listen(sServer, 1);
if (retVal == SOCKET_ERROR){
printf("listen failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 接受客户请求
printf("TCP Server start...!\n");
SOCKADDR_IN addrClient;//客户端地址
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen);
if (sClient == INVALID_SOCKET){
printf("accept failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 循环接收客户端的数据,直接客户端发送了10次数据后退出。
int count = 1;
while (count<2)
{
ZeroMemory(buf, BUF_SIZE); // 清空接收数据的缓冲区
//接收数据
retVal = recv(sClient, buf, BUFSIZ, 0);
//———————————————————————增加内容—————
if (retVal > 0){
printf("\nrecv函数调用成功,在服务器端显示客户端的IP地址:%s \r\n", inet_ntoa(addrClient.sin_addr));
}
if (retVal == 0){
printf("连接已经关闭");
}
//————————————————————————————————
if (retVal == SOCKET_ERROR){
printf("recv failed!\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
// 获取当前系统时间
SYSTEMTIME st;
GetLocalTime(&st);
char sDateTime[30];
sprintf_s(sDateTime, "%4d-%2d-%2d %2d:%2d:%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
// 打印输出的信息
printf("%s, Recv From Client [%s:%d] :%s\n", sDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf);
//向客户端发送回复消息
printf("Please input a string to send to client: ");
// 接收输入的数据
std::string str;
std::getline(std::cin, str);
getchar();
// 将用户输入的数据复制到buf中
ZeroMemory(buf, BUF_SIZE);
strcpy_s(buf, str.c_str());
// 向服务器发送数据
char msg[BUF_SIZE];
sprintf_s(msg, " %s", buf);
retVal = send(sClient, msg, strlen(msg), 0);
if (SOCKET_ERROR == retVal)
{
printf("send failed !\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
printf("---------第 %d 次对话结束-----------\n", count);
count++;
}
//服务器退出 释放套接字
closesocket(sServer);
closesocket(sClient);
WSACleanup();
// 暂停,按任意键退出
system("pause");
return 0;
}
// 大作业客户端.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Winsock2.H>
#include <string>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 65535 // 缓冲区大小
int main(int argc, CHAR* argv[])
{
WSADATA wsd; // 用于初始化Windows Socket
SOCKET sHost; // 与服务器进行通信的套接字
SOCKADDR_IN servAddr; // 服务器地址
//SOCKET sServer; // 服务器套接字,用于监听客户端请求
//SOCKET sClient; // 客户端套接字,用于实现与客户端的通信
char buf[BUF_SIZE]; // 用于接受数据缓冲区
int retVal; // 调用各种Socket函数的返回值
// 初始化Windows Socket
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){
printf("WSAStartup failed!\n");
return -1;
}
// 创建套接字
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost){
printf("socket failed!\n");
WSACleanup();
return -1;
}
// 设置服务器地址
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.43.62"); // 用户需要根据实际情况修改
servAddr.sin_port = htons(9990);// 在实际应用中,建议将服务器的IP地址和端口号保存在配置文件中
int sServerAddlen = sizeof(servAddr);// 计算地址的长度
// 连接服务器
retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));
if (retVal == SOCKET_ERROR){
printf("connect failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
}
// 循环向服务器发送字符串,并显示反馈信息。
// 发送quit将使服务器程序退出,同时客户端程序自身也将退出
int count = 1;
while (count<2)
{
// 向服务器发送数据
printf("Please input a string to send: ");
// 接收输入的数据
std::string str;
std::getline(std::cin, str);
getchar();
// 将用户输入的数据复制到buf中
ZeroMemory(buf, BUF_SIZE);
strcpy_s(buf, str.c_str());
// 向服务器发送数据
retVal = send(sHost, buf, strlen(buf), 0);
if (SOCKET_ERROR == retVal)
{
printf("send failed !\n");
closesocket(sHost);
WSACleanup();
return -1;
}
ZeroMemory(buf, BUF_SIZE);// 清空接收数据的缓冲区
// 接收服务器回传的数据
retVal = recv(sHost, buf, BUFSIZ, 0);
//————————————————————————————————增加内容————————
if (retVal > 0){
printf("\nrecv函数调用成功,在客户端显示服务器的IP地址:%s \r\n", inet_ntoa(servAddr.sin_addr));
}
if (retVal == 0){
printf("连接已经关闭");
}
//————————————————————————————————————————
printf("Message aply : %s\n", buf);
printf("---------第 %d 次对话结束-----------\n", count);
count++;
}
// 释放资源
closesocket(sHost);
WSACleanup();
// 暂停,按任意键继续
system("pause");
return 0;
}