TCP客户端与服务器通信,非阻塞模式,程序填空,运行服务器闪退?求改错

罗爱我 2016-06-15 09:40:18
// TcpClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <Winsock2.H>
#include <string>
#include <iostream>

#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 64 // 缓冲区大小

int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsd; // 用于初始化Windows Socket
SOCKET sHost; // 与服务器进行通信的套接字
SOCKADDR_IN servAddr; // 服务器地址
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("127.0.0.1"); // 用户需要根据实际情况修改
servAddr.sin_port = htons(9990); // 在实际应用中,建议将服务器的IP地址和端口号保存在配置文件中
int sServerAddlen = sizeof(servAddr); // 计算地址的长度
// 连接服务器
retVal = connect(sHost,(LPSOCKADDR)&servAddr,sizeof(servAddr));

// 循环等待

while(true)
{


if(INVALID_SOCKET == sHost)
{
int err = WSAGetLastError();
if(err == WSAEWOULDBLOCK) // 无法立即完成非阻塞套接字上的操作
{
//Sleep(500);

continue;
}
else
{
printf("accept failed !\n");
closesocket(sHost);
WSACleanup();
return -1;
}
}
}

// 循环向服务器发送字符串,并显示反馈信息。
// 发送quit将使服务器程序退出,同时客户端程序自身也将退出
while(true)
{
// 向服务器发送数据
printf("Please input a string to send: ");
// 接收输入的数据
std::string str;
std::getline(std::cin, str);
// 将用户输入的数据复制到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;
}
// 接收服务器回传的数据
retVal=recv(sHost,buf,sizeof(buf)+1,0);
printf("Recv From Server: %s\n",buf);
// 如果收到quit,则退出
if(strcmp(buf, "quit") == 0)
{
printf("quit!\n");
break;
}
}
// 释放资源
closesocket(sHost);
WSACleanup();
// 暂停,按任意键继续
system("pause");
return 0;
}
============================================
// TcpServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <WINSOCK2.H>
#include <iostream>

#pragma comment(lib,"WS2_32.lib")
#define BUF_SIZE 64 // 缓冲区大小

int _tmain(int argc, _TCHAR* 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;
}
// 创建用于监听的套接字
1. sServer =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == sServer)
{
printf("socket failed !\n");
WSACleanup();
return -1;
}
// 设置套接字为非阻塞模式
int iMode = 1;
2.retVal =ioctlsocket(sServer,FIONBIO,(u_long FAR*) &iMode);
if(retVal == SOCKET_ERROR)
{
printf("ioctlsocket failed !\n");
WSACleanup();
return -1;
}

// 设置服务器套接字地址
SOCKADDR_IN addrServ;
addrServ.sin_family = AF_INET;
3. addrServ.sin_port=htons(9990); // 监听端口为9990
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
// 绑定套接字sServer到本地地址,端口9990
4. retVal=bind(sServer,(const struct sockaddr*)&addrServ,sizeof(SOCKADDR_IN));
if(SOCKET_ERROR == retVal)
{
printf("bind failed !\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 监听套接字
retVal = listen(sServer,1);
if(SOCKET_ERROR == retVal)
{
printf("listen failed !\n");
5. 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(INVALID_SOCKET == sClient)
{
printf("accept failed !\n");
closesocket(sServer);
WSACleanup();
return -1;
}
// 循环接收客户端的数据,直接客户端发送quit命令后退出。
while(true)
{
ZeroMemory(buf,BUF_SIZE);
retVal = recv(sClient,buf,BUFSIZ,0); //
if(SOCKET_ERROR == retVal)
{
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);
// 如果客户端发送quit字符串,则服务器退出
if(strcmp(buf, "quit") == 0)
{
6.retVal =send(sClient,"quit",strlen("quit"),0);
break;
}
else // 否则向客户端发送回显字符串
{
7.char msg[BUF_SIZE];
sprintf_s(msg, "Message received - %s", buf);
retVal = send(sClient, msg, strlen(msg),0);
if(SOCKET_ERROR == retVal)
{
printf("send failed !\n");
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return -1;
}
}
}
// 释放套接字
closesocket(sServer);
closesocket(sClient);
WSACleanup();
// 暂停,按任意键退出
system("pause");
return 0;
}
...全文
196 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
cutmelon 2016-06-16
  • 打赏
  • 举报
回复
这题面本身就不是什么好东西,对于tcp的socket来说就是误人子弟。。。
赵4老师 2016-06-16
  • 打赏
  • 举报
回复
个人意见:用填空题考程序理解能力纯属脑残!
夜鹰 2016-06-16
  • 打赏
  • 举报
回复
#由Windows版移至C语言
1、本课程是一个干货课程,主要讲解如何封装服务器底层,使用Tcp/ip长连接,IDE使用vs2019 c++开发以及使用c++11的一些标准,跨平台windows和linux,服务器性能高效,单服务器压力测试上万无压力,服务器框架是经历过上线产品的验证,框架简单明了,不熟悉底层封装的人,半个小时就能完全掌握服务器框架上手写业务逻辑。2、本课程是一个底层服务器框架教程,主要是教会学员在windows或linux下如何封装一个高效的,避免踩坑的商业级框架,服务器底层使用初始化即开辟内存的技术,使用内存池,服务器运行期间内存不会溢出,非常稳定,同时服务器使用自定义哈希hashContainer,在处理新的连接,新的数据,新的封包,以及解包,发包,粘包的过程,哈希容器性能非常高效,增、删、查、改永远不会随着连接人数的上升而降低性能,增、删、查、改的复杂度永远都是恒定的O(1)。3、服务器底层封装没有使用任何第三方网络库以及任何第三方插件,自由度非常的高,出了任何BUG,你都有办法去修改,查找问题也非常方便,在windows下使用iocp,linux下使用epoll.4、讲解c++纯客户端,主要用于服务器之间通信,也就是说你想搭建多层结构的服务器服务器服务器之间使用socket通信。还可以使用c++客户端做压力测试,开辟多线程连接服务器,教程提供了压力测试,学员可以自己做压力测试服务器性能。5、赠送ue4和unity3d通信底层框架以及多人交互demo,登录,注册,玩家离开,同步主要是教会学员服务器客户端如何交互。6、赠送c++连接mysql数据库框架demo,登录,注册,玩家离开数据持久化.7、服务器教程使用自定义通信协议,同时也支持protobuf,选择权在开发者自己手里,想用什么协议都可以,自由度高。8、服务器教程使用手动敲代码逐句讲解的方式开展教学课程。非喜勿喷,谢谢大家。9、服务器教程提供源码,大家可以在平台提供的地址下载或者联系我,服务器使用c++11部分标准,std::thread,条件变量,线程锁,智能指针等,需要学员具备一定c++知识,购买前请慎重考虑。

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧