Windows下TCP聊天服务器与客户端雏形的实现
来源:互联网 发布:程序员初级职称 编辑:程序博客网 时间:2024/05/18 03:11
摘要
在学习游戏服务器搭建的过程中,需要使用Windows搭建TCP服务器与客户端,这里记录下遇到的错误与 所写的代码。
在blog最后bia了一个很挫的DEMO,仅供参考,后续解决后会继续发上来
服务器端
首先需要包含所需的头文件winsock2.h和ws2tcpip.h;
然后需要连接Winsock API 链接库文件ws2_32.lib,有以下两种方法
// (1) PRO文件中定义LIBS += -lpthread libwsock32 libws2_32// (2) Pragma#pragma comment(lib,"ws2_32.lib")
- (1) 初始化阶段调用WSAStartup函数,此函数在程序中初始化Windows Socket DLL,只有此函数调用成功后,程序才可以调用别的API:
WSADATA wsaData;int nRet;if((nRet = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0){ exit(0);}
- (2) 创建Socket
SOCKET s;s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 使用流Socket,基于TCP协议
- (3) 绑定端口
SOCKADDR_IN ServerAddr;ServerAddr.sin_family = AF_INET;ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1");ServerAddr.sin_port = htons(9000);ret = ::bind(s, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));if(ret == SOCKET_ERROR){ error = WSAGetLastError(); std::cout<<"Binding Failed!"<<error<<std::endl; closesocket(s); s = NULL; WSACleanup(); break;}
如果使用者不在意地址或者端口的值,那么可以设定地址为INADDR_ANY,即Port为0,然后可以调用getsockname()来获知其被系统自动设定的值
SOCKADDR_IN ServerAddr;ServerAddr.sin_family = AF_INET;ServerAddr.sin_addr_s_addr = htonl(INADDR_ANY);addr.sin_port = htons(0);::bind(s, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
- (4) 监听
ret = listen(s,SOMAXCONN);if(ret == SOCKET_ERROR){ error = WSAGetLastError(); std::cout<<"Listening Failed!"<<error<<std::endl; closesocket(s); s = NULL; WSACleanup(); break;}
- (5) 接受请求
SOCKET temp;temp = ::accept(s, (SOCKADDR*)&ServerAddr, (socklen_t*)&len);
客户端
与服务端的区别在于没有了bind,但是需要connect
if(::connect(s, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR){ std::cout<<"Connecting Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); WSACleanup(); return;}else{ std::cout<<"Connecting Succfully!"<<std::endl;}
一个简单的QT聊天软件
服务器端
(1)头文件
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QAction>#include <QLabel>#include <QMenu>#include <QSlider>#include <QLineEdit>#include <QPushButton>#include <QScrollArea>#include <QGridLayout>#include <QMenuBar>#include <QTimer>#include <QFileDialog>#include <QMessageBox>#include <QApplication>#include <winsock2.h>#include <ws2tcpip.h>#include <iostream>#include <string>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{ Q_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); ~MainWindow();private slots: void start_connect();private: QWidget *centralWidget; QWidget *displayWidget; QWidget *controlWidget; QScrollArea *controlArea; QPushButton *button_connect; QLineEdit *edit_port; QLabel *lable_connetion_status;};#endif // MAINWINDOW_H
(2) cpp文件
#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ // Initiation of CentrlWidget centralWidget = new QWidget; setGeometry(100,100,1200,768); setWindowTitle("Fabric Simulator"); setCentralWidget(centralWidget); // Initiation of displayWidget displayWidget = new QWidget; displayWidget->setSizeIncrement(500,768); QGridLayout *displayLayout = new QGridLayout; displayWidget->setLayout(displayLayout); // Initiation of ConsoleWidget controlWidget = new QWidget; button_connect = new QPushButton("Start Connection"); connect(button_connect, SIGNAL(clicked()), this, SLOT(start_connect())); edit_port = new QLineEdit("9000"); edit_port->setPlaceholderText("port"); lable_connetion_status = new QLabel("Con Status:"); QGridLayout *controlLayout = new QGridLayout; controlLayout->addWidget(edit_port,0,0,1,1); controlLayout->addWidget(button_connect,1,0,1,1); controlLayout->addWidget(lable_connetion_status,2,0,1,1); controlWidget->setLayout(controlLayout); controlArea = new QScrollArea; controlArea->setWidget(controlWidget); controlArea->setWidgetResizable(true); controlArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); controlArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); controlArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); controlArea->setMinimumSize(50, 50); //将控件加入到主Widget里去 QGridLayout *centralLayout = new QGridLayout; //centralLayout->addWidget(openGLWidgetArea, 0, 0, 1, 3); centralLayout->addWidget(displayWidget,0, 0, 1, 3); centralLayout->addWidget(controlArea, 0, 1, 1, 3); centralWidget->setLayout(centralLayout);}//SLOT Implementationvoid MainWindow::start_connect(){ // !!注意:在Windows下执行socket相关操作前,必须初始化WSADATA!!!! WSADATA wsaData; int nRet; if((nRet = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0){ exit(0); } // (1) 初始化监听Socket SOCKET s; if((s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){ // 使用流Socket,基于TCP协议 std::cout<<"Socket Initiation Failed!"<<WSAGetLastError()<<std::endl; return; }else{ std::cout<<"Socket Initiation Successfully!"<<std::endl; } SOCKADDR_IN ServerAddr; ServerAddr.sin_family = AF_INET; int port = this->edit_port->text().toInt(); ServerAddr.sin_port = htons(port); ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // (2)绑定Socket if(::bind(s, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR){ std::cout<<"Binding Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); s = NULL; WSACleanup(); return; }else{ std::cout<<"Binding Succfully!"<<std::endl; } // (3)开始监听 if(SOCKET_ERROR == ::listen(s, SOMAXCONN)){ std::cout<<"Start Listening Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); s = NULL; WSACleanup(); return; }else{ std::cout<<"Start Listening Succfully On Port: "<<port<<std::endl; this->lable_connetion_status->setText(QString("Con Status: Listening Succfully On Port:"+this->edit_port->text())); } // (4)检测新连接 int len = sizeof(ServerAddr); while(1){ //循环等待新连接 SOCKET temp = accept(s, (SOCKADDR*)&ServerAddr, (socklen_t*)&len); if(temp == INVALID_SOCKET){ //链接失败 std::cout<<"New Connection Established Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); s = NULL; WSACleanup(); break; }else{ std::cout<<"New Connection Established Successfully!"<<std::endl; while(1){ char buf[256]; memset(buf, 0, sizeof(buf)); int ret = recv(temp, buf, 256, 0); if(ret==0 || ret == SOCKET_ERROR){ std::cout<<"Received Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(temp); break; } std::string str = std::string(buf); std::cout<<str<<std::endl; } } } ::closesocket(s); s = NULL; WSACleanup(); std::cout<<"Socket Finished!"<<std::endl;}MainWindow::~MainWindow(){}
客户端
(1)头文件
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QAction>#include <QLabel>#include <QMenu>#include <QSlider>#include <QLineEdit>#include <QPushButton>#include <QScrollArea>#include <QGridLayout>#include <QMenuBar>#include <QTimer>#include <QFileDialog>#include <QMessageBox>#include <QApplication>#include <winsock2.h>#include <ws2tcpip.h>#include <iostream>#include <string>namespace Ui {class MainWindow;}class MainWindow : public QMainWindow{ Q_OBJECTpublic: explicit MainWindow(QWidget *parent = 0); ~MainWindow();private slots: void start_connect(); void close_connect(); void send_message();private: SOCKET s; QWidget *centralWidget; QWidget *displayWidget; QWidget *controlWidget; QScrollArea *controlArea; QPushButton *button_connect; QPushButton *button_close; QPushButton *button_send; QLineEdit *edit_address; QLineEdit *edit_port; QLineEdit *edit_message; QLabel *lable_connetion_status;};#endif // MAINWINDOW_H
(2)cpp文件
#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ // Initiation of CentrlWidget centralWidget = new QWidget; setGeometry(100,100,1200,768); setWindowTitle("Fabric Simulator"); setCentralWidget(centralWidget); // Initiation of displayWidget displayWidget = new QWidget; displayWidget->setSizeIncrement(500,768); QGridLayout *displayLayout = new QGridLayout; displayWidget->setLayout(displayLayout); // Initiation of ConsoleWidget controlWidget = new QWidget; button_connect = new QPushButton("Start Connection"); connect(button_connect, SIGNAL(clicked()), this, SLOT(start_connect())); button_close = new QPushButton("Close Connection"); connect(button_close, SIGNAL(clicked()), this, SLOT(close_connect())); button_send = new QPushButton("send"); connect(button_send, SIGNAL(clicked()), this, SLOT(send_message())); edit_port = new QLineEdit("9000"); edit_port->setPlaceholderText("port"); edit_message = new QLineEdit(""); edit_message->setPlaceholderText("message"); lable_connetion_status = new QLabel("Con Status:"); QGridLayout *controlLayout = new QGridLayout; controlLayout->addWidget(edit_port,0,0,1,2); controlLayout->addWidget(button_connect,1,0,1,2); controlLayout->addWidget(button_close,2,0,1,2); controlLayout->addWidget(edit_message,3,0,1,1); controlLayout->addWidget(button_send,3,1,1,1); controlLayout->addWidget(lable_connetion_status,4,0,1,2); controlWidget->setLayout(controlLayout); controlArea = new QScrollArea; controlArea->setWidget(controlWidget); controlArea->setWidgetResizable(true); controlArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); controlArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); controlArea->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); controlArea->setMinimumSize(50, 50); //将控件加入到主Widget里去 QGridLayout *centralLayout = new QGridLayout; //centralLayout->addWidget(openGLWidgetArea, 0, 0, 1, 3); centralLayout->addWidget(controlArea, 0, 0, 1, 3); centralWidget->setLayout(centralLayout);}//SLOT Implementationvoid MainWindow::start_connect(){ // !!注意:在Windows下执行socket相关操作前,必须初始化WSADATA!!!! WSADATA wsaData; int nRet; if((nRet = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0){ std::cout<<"WSA Initiation Failed!"<<WSAGetLastError()<<std::endl; return; } // (1) 初始化Socket // SOCKET s; if((s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){ // 使用流Socket,基于TCP协议 std::cout<<"Socket Initiation Failed!"<<WSAGetLastError()<<std::endl; return; }else{ std::cout<<"Socket Initiation Successfully!"<<std::endl; } // 设置目标服务器的地址 SOCKADDR_IN ServerAddr; ServerAddr.sin_family = AF_INET; int port = this->edit_port->text().toInt(); ServerAddr.sin_port = htons(port); ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // (2)连接服务器 if(::connect(s, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR){ std::cout<<"Connecting Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); WSACleanup(); return; }else{ std::cout<<"Connecting Succfully!"<<std::endl; }}void MainWindow::close_connect(){ if(s!=NULL){ ::closesocket(s); s = NULL; WSACleanup(); } std::cout<<"Connection Closed!"<<std::endl;}void MainWindow::send_message(){ // (3)发送消息 int ret; std::string str = edit_message->text().toStdString(); const char* ch = str.c_str(); if((ret=::send(s, ch , strlen(ch) , 0))==SOCKET_ERROR){ std::cout<<"Message Sending Failed!"<<WSAGetLastError()<<std::endl; ::closesocket(s); s = NULL; WSACleanup(); }else{ std::cout<<"Message Sending Successfully!"<<std::endl; }}MainWindow::~MainWindow(){}
如果发送成功:
服务器端就会显示客户端发来的信息:
总结
这个Demo实在很粗糙,而且不具有实用性,但是对于熟悉TCP通信基础来说已经足够了,有以下问题需要解决:
(1) 阻塞问题
(2) 多个用户连接(maybe 多线程)
阅读全文
1 0
- Windows下TCP聊天服务器与客户端雏形的实现
- 初探基于TCP的服务器/客户端结构的聊天系统(三)之表情聊天的实现
- 初探基于TCP的服务器/客户端结构的聊天系统(四)视频聊天的实现
- C#下如何实现服务器+客户端的聊天程序
- C#下如何实现服务器+客户端的聊天程序
- C#下如何实现服务器+客户端的聊天程序
- C#下如何实现服务器+客户端的聊天程序
- C# 网络编程之Tcp实现客户端和服务器聊天
- C#网络编程之 TCP实现客户端和服务器聊天
- Java 实现TCP网络聊天[服务器-客户端]UI界面
- C语言学习之Linux下TCP服务器与客户端的实现
- 初探基于TCP的服务器/客户端结构的聊天系统
- TCP协议下---客户端与服务端一问一答聊天
- Windows 下利用FTP实现客户端与服务器文件传输
- (TCP模式下)客户端与服务器交互
- Linux客户端与服务器相互实现聊天功能
- Unix网络编程之点对点聊天-客户端与服务器实现
- 能够与服务器连接交互的拥有界面的客户端-------------聊天窗口(实现群聊)
- android中的ANR异常
- 冒泡排序
- 基于Spark ALS在线推荐系统
- 基于89C51和STM32F1实现2.4G无线射频智能家居
- wampserver环境下配置虚拟域名
- Windows下TCP聊天服务器与客户端雏形的实现
- Python中的Numpy入门教程
- bashTomcat02
- 不需要新发卡的一卡通系统全新设计解决思路
- Climbing Stairs
- JVM源码分析之线程局部缓存TLAB
- Lake Counting(搜索之DFS)
- 最长单词
- Queryable States in ApacheFlink