Linux系统编程:
udp 接收端:
socket(AF_INET, SOCK_DGRAM, 0);
bind(..)
recvfrom(…)
udp发送端:
socket(...)
sendto(..); // udp 也可以connect ,但不是连接,仅是指定目标IP,端口号而已
// connect后就可以write, send
//
tcp服务端:
socket(AF_INET, SOCK_STREAM, 0);
bind(..)
listen(..)
accept(..)
tcp客户端:
socket();
connect();
udp是无连接,tcp是连接的。
什么是连接, 其实就是与每个客户端有没有需要单独的处理。如在Linux系统编程,udp不管多少个客户端发过来数据,服务端都只调用recvfrom函数就可以,用不着分开客户端来处理。在tcp里,客户端在服务端都是由一个不同的文件描述符来的区分的,在服务端操作不同的文件描述符就意味着与不同的客户端通信。
在QT里, udp和tcp 都封装成类. 其实就是把linux系统的网络编程封装成类.
Udp : QUdpSocket
tcp: QTcpServer, QTcpSocket
udp用法:
1不管是发送端或接收端都需要创建一个QUdpSocket对象(创建对象时,内部会socket());
2 发送端直接调用对象的writeDatagram就可以了, 发出数据后也会有bytesWritten()信号。
3 接收端还需bind, 然后当有数据需接收处理,会有readyRead()信号,再调用readDatagram接收数据.
Qt里的udp默认就可以支持广播功能,只要往广播地址发送数据即可实现。
利用udp广播实现网络聊天室:
pro工程文件里: QT += gui core widgets network
mywin.h
#ifndef MYWIN_H
#define MYWIN_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QUdpSocket>
#define PORT 7788
class MyWin : public QWidget
{
Q_OBJECT
private:
QTextEdit *txt; //用于显示接收到内容
QLineEdit *lnd_ip; //用于接收用户发送数据的目标IP
QLineEdit *lnd_send; //接收要发送的数据
QLabel *lbl_ip;
QLabel *lbl_send;
QPushButton *btn_send; //发送按钮
QHBoxLayout *hlayout;
QVBoxLayout *vlayout;
QUdpSocket *udp;
public:
explicit MyWin(QWidget *parent = 0);
~MyWin();
signals:
public slots:
void slot_btn();
void slot_udp_recv();
};
#endif // MYWIN_H
mywin.cpp
#include "mywin.h"
#include <QMessageBox>
#include <QDebug>
MyWin::MyWin(QWidget *parent) : QWidget(parent)
{
//初始化界面
txt = new QTextEdit;
lnd_ip = new QLineEdit("192.168.250.255"); //默认广播地址
lnd_send = new QLineEdit("hello udp");
btn_send = new QPushButton("send");
lbl_ip = new QLabel("ip:");
lbl_send = new QLabel("text:");
hlayout = new QHBoxLayout;
hlayout->addWidget(lbl_ip, 1);
hlayout->addWidget(lnd_ip, 3);
hlayout->addWidget(lbl_send, 1);
hlayout->addWidget(lnd_send, 4);
hlayout->addWidget(btn_send, 1);
vlayout = new QVBoxLayout(this);
vlayout->addWidget(txt, 8);
vlayout->addLayout(hlayout, 2);
resize(640, 480);
///
// udp对象初始化
udp = new QUdpSocket(this);
if (!udp->bind((PORT)))//绑定端口号
{
QMessageBox::critical(this, "error", "bind failed");
exit(0);
}
//连接按钮的单击信号
connect(btn_send, SIGNAL(clicked(bool)), this, SLOT(slot_btn()));
// 连接udp对象的readyRead信号
connect(udp, SIGNAL(readyRead()), this, SLOT(slot_udp_recv()));
}
MyWin::~MyWin()
{
delete txt;
delete lnd_ip;
delete lnd_send;
delete lbl_ip;
delete lbl_send;
delete hlayout;
delete vlayout;
delete udp;
}
void MyWin::slot_btn()
{
//发送数据
QString str = lnd_send->text();
QString ip = lnd_ip->text();
udp->writeDatagram(str.toUtf8(), QHostAddress(ip), PORT); //发出的数据是utf8编码
}
void MyWin::slot_udp_recv()
{
char *data;
int ret , len = udp->pendingDatagramSize()+1;
QHostAddress peer; //用于接收对方的IP地址
quint16 port;
QString ip, str("%1[%2]:%3"); //表示此字符是由三个参数组成的
data = new char[len];
ret = udp->readDatagram(data, len, &peer, &port); //接收数据,并存放对方的IP地址端口号
if (ret <= 0)
return;
data[ret] = 0; //设尾0
// ip[port] : data
// ip地址默认是64位,需转成32位
ip = QHostAddress(peer.toIPv4Address()).toString(); //用32位的地址创建对象,再获取地址
str = str.arg(ip).arg(port).arg(data);
txt->append(str);
txt->moveCursor(QTextCursor::End); //自动翻到最后一行
}
main.cpp
#include <QApplication>
#include "mywin.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWin win;
win.show();
return a.exec();
}