socket通讯编程
传输层协议。包括传输控制协议TCP和用户数据报文协议UDP。
传输控制协议(TCP)。由于IP 提供非连接型传递服务,因此TCP应为应用程序存取网络创造了条件,使用可靠的面向连接的传输层服务。该协议为建立网际上用户进程之间的对话负责。此外,还确保两个以上进程之间的可靠通信。它所提供的功能如下:
1.监听输入对话建立请求。
2.请求另一网络站点对话。
3.可靠的发送和接收数据。
4.适度的关闭对话。
三次握手:
可以简化为对讲机:
A->B(发送消息确认B是否可以收到)
B->A(发送信息,回复自己是否可以收到,并且确定对方是否可以接收到自己的消息)
A->B(发送消息回应B自己可以收到消息)
A–协议/约定—>B
B<—协议/约定—A
有两个地址
源地址:数据从哪来
目的地址:数据往哪去
由此可见UDP并不安全 Socket既是一种特殊的IO,它也是一种文件描述符。一个完整的Socket
都有一个相关描述{协议,本地地址,本地端口,远程地址,远程端口};每一个Socket 有一个本地的唯一Socket 号,由操作系统分配。
在linux上实现C/S模型
servce.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main(void)
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i, n;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 20);
printf("Accepting connections ...\n");
while (1) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);
n = read(connfd, buf, MAXLINE);
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port));
for (i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
write(connfd, buf, n);
close(connfd);
}
}
client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd, n;
char *str;
if (argc != 2) {
fputs("usage: ./client message\n", stderr);
exit(1);
}
str = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
write(sockfd, str, strlen(str));
n = read(sockfd, buf, MAXLINE);
printf("Response from server:\n");
write(STDOUT_FILENO, buf, n);
close(sockfd);
return 0;
}
在QT上实现客户端,linux上实现服务端。
1.查找linux上的地址,虚拟机的网络设置为桥接
2.关闭防火墙
QT:
首先要在pro上加上network
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QtNetwork>
#include <QTcpSocket>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
QLabel *Ip_label;
QLabel *Port_label;
QLineEdit *Ip_Edit;
QLineEdit *Port_Edit;
QPushButton *connect_btn;
QPushButton *close_btn;
QTcpSocket *tcpclient;
private slots:
void connect_slot();
void slot_connected();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
Ip_label =new QLabel(this);
Ip_label->move(70,80);
Ip_label->setText("IP");
Port_label=new QLabel(this);
Port_label->move(70,130);
Port_label->setText("port");
Ip_Edit =new QLineEdit(this);
Ip_Edit->move(140,80);
Ip_Edit->setPlaceholderText("please input ip");
Port_Edit=new QLineEdit(this);
Port_Edit->move(140,130);
Port_Edit->setPlaceholderText("please input port");
connect_btn =new QPushButton(this);
connect_btn->move(70,200);
connect_btn->setText("yes");
close_btn=new QPushButton(this);
close_btn->move(220,200);
close_btn->setText("back");
connect(connect_btn,SIGNAL(clicked()),this,SLOT(connect_slot()));
}
Widget::~Widget()
{
}
void Widget::connect_slot()
{
tcpclient =new QTcpSocket(this); //初始化socket
// tcpclient->abort(); //终止之前的连接,重置套接字
this->tcpclient->connectToHost(Ip_Edit->text(),6666);
// connect(tcpclient,SIGNAL(connected()),this,SLOT(slot_connected()));
}
void Widget::slot_connected()
{
}
main.cpp
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
LINUX:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define portnumber 6666
int main(int argc, char *argv[])
{
int sockfd,new_fd;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int sin_size;
int nbytes;
char buffer[1024];
/* 服务器端开始建立sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) // AF_INET:IPV4; SOCK_STREAM:TCP
{
fprintf(stderr,"Socket error:%s\n\a",strerror(errno));
exit(1);
}
//设置Socket属性:SO_REUSEADDR:允许在bind过程中本地地址重复使用
int iSockopt = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&iSockopt, sizeof(int)) < 0 )
{
close(sockfd);
return -1;
}
/* 服务器端填充 sockaddr结构 */
bzero(&server_addr,sizeof(struct sockaddr_in)); // 初始化,置0
server_addr.sin_family=AF_INET; // Internet
server_addr.sin_addr.s_addr=INADDR_ANY; //INADDR_ANY 表示可以接收任意IP地址的数据,即绑定到所有的IP
//server_addr.sin_addr.s_addr=inet_addr("192.168.1.1");
//用于绑定到一个固定IP,inet_addr用于把数字加格式的ip转化为整形ip
server_addr.sin_port=htons(portnumber); // (将本机器上的short数据转化为网络上的short数据)端口号
/* 捆绑sockfd描述符到IP地址 */
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Bind error:%s\n\a",strerror(errno));
exit(1);
}
/* 设置允许连接的最大客户端数 */
if(listen(sockfd,5)==-1)
{
fprintf(stderr,"Listen error:%s\n\a",strerror(errno));
exit(1);
}
while(1)
{
/* 服务器阻塞,直到客户程序建立连接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
{
fprintf(stderr,"Accept error:%s\n\a",strerror(errno));
exit(1);
}
fprintf(stderr,"Server get connection from %s\n",inet_ntoa(client_addr.sin_addr)); // 将网络地址转换成.字符串
if((nbytes=read(new_fd,buffer,1024))==-1)
{
fprintf(stderr,"Read Error:%s\n",strerror(errno));
exit(1);
}
buffer[nbytes]='\0';
printf("Server received %s\n",buffer); //这个通讯已经结束
close(new_fd); /* 循环下一个 */
} /* 结束通讯 */
close(sockfd);
exit(0);
}
makefile
.PHONY: clean all
CC = gcc
CXX = g++
CPPFLAGS = -Wall -Wno-deprecated
LDFLAGS = -lpthread -lrt -lsqlite3
BINSRCS := main.cpp
SRCS := $(wildcard *.cpp)
SRCS := $(filter-out $(BINSRCS),$(SRCS))
BIN = main
all: $(BIN)
main: $(SRCS) main.cpp
$(CXX) $(CPPFLAGS) $^ -o $@ $(LDFLAGS)
%.o:%.cpp
$(CXX) $(CPPFLAGS) -c $<
%.o:%.c
$(CC) -c $<
clean:
-rm -rf $(BIN) *.o