1 前期准备
系统:Ubuntu系统
1.1 TCP
TCP:传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
使用socke实现TCP通信,需要准备下列参数:
- 服务端:源端口+ ip地址
- 客户端:服务端源端口 + 服务端ip地址
1.2 获取ip地址
//windos系统
$ ipconfig
......
无线局域网适配器 WLAN:
连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::5eff:f43f:cb33:c275%2
IPv4 地址 . . . . . . . . . . . . : 192.168.0.101
子网掩码 . . . . . . . . . . . . : 255.255.255.0
......
//Ubuntu系统
$ ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.109 netmask 255.255.255.0 broadcast 192.168.0.255
2 socket编写服务端
2.1 创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == serv_sock)
{
std::cout<<"socket() 失败"<<std::endl;
return -1;
}
2.2 绑定服务端IP地址、端口等信息到套接字上
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("192.168.0.109"); //服务端的ip地址
serv_addr.sin_port = htons(1886); //端口范围在1024~65535间
if(bind(serv_sock, (struct sockaddr*)&serv_addr,sizeof(serv_addr)) <0 )
{
std::cout<<"bind() 失败"<<std::endl;
return -1;
}
2.3 开启监听,等待客户端发起请求
if (listen(serv_sock, 20) <0 )
{ //服务端套接字,同时能够允许多少个客户端连接
std::cout<<"listen() 失败"<<std::endl;
return -1;
}
std::cout<<"服务端启动监听"<<std::endl;
2.4 接受客户端的连接
struct sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
int client_sock = accept(serv_sock, (struct sockaddr*)&client_addr, &client_addr_size);
//client_sock套接字增加了客户端的ip 和 端口等信息
if(client_sock <0)
{
std::cout<<"accept() 失败"<<std::endl;
return -1;
}
2.5 使用建立连接的套接字,收发数据
char sendbuf[1024] ="Hello world";
write(client_sock,sendbuf,strlen(sendbuf)+1);
char recvbuf[1024]= {'\0'};
int read_len;
read_len = read(client_sock,recvbuf,strlen(recvbuf)+1);
2.6 关闭网络连接
close(client_sock);
close(serv_sock);
tcp_server.cpp文件
#include <netinet/in.h>
#include <sys/types.h> //<sys/types.h>依赖头文件<netinet/in.h>
#include <sys/socket.h> //<sys/socket.h>依赖头文件<sys/types.h>
#include <arpa/inet.h> //inet_addr()的头文件
#include <unistd.h> //socklen_t的头文件
#include <iostream>
#include <string.h>
int main()
{
//1. 创建套接字 ,TCP使用的协议SOCK_STREAM
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == serv_sock)
{
std::cout<<"socket() 失败"<<std::endl;
return -1;
}
//2 绑定服务端IP地址、端口等信息到套接字上
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("192.168.0.109"); //服务端的ip地址
serv_addr.sin_port = htons(1886); //端口范围在1024~65535间
if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) <0 )
{
std::cout<<"bind() 失败"<<std::endl;
return -1;
}
// 3 开启监听状态,等待客户端发起请求 →监听套接字
if (listen(serv_sock, 20) <0 )
{ //服务端套接字,同时能够允许多少个客户端连接
std::cout<<"listen() 失败"<<std::endl;
return -1;
}
std::cout<<"服务端启动监听"<<std::endl;
//4 接收客户端请求
struct sockaddr_in client_addr;
socklen_t client_addr_size = sizeof(client_addr);
int client_sock = accept(serv_sock, (struct sockaddr*)&client_addr, &client_addr_size);
//client_sock套接字增加了客户端的ip 和 端口等信息
if(client_sock <0)
{
std::cout<<"accept() 失败"<<std::endl;
return -1;
}
std::cout<<"已成功建立连接"<<std::endl;
//5 收发数据,每次均需指定地址信息
char sendbuf[1024] ="Hello world";
write(client_sock,sendbuf,strlen(sendbuf)+1);
close(client_sock);
close(serv_sock);
return 0;
}
3 socket编写客户端
3.1 创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
3.2 设置服务端的IP地址和端口等属性
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("192.168.0.109"); //服务端的IP地址
serv_addr.sin_port = htons(1886); //服务端的端口号
3.3 发送连接请求
int res = connect(serv_sock ,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(res==-1)
{
std::cout<<" connect()失败";
return -1;
}
3.4 使用建立好连接的套接字,收发数据
char buffer[] = "hello,这里是客户端";
while(true)
{
write(serv_sock,buffer,sizeof(buffer));
}
char revbuffer[1024] ={'\0'};
read(serv_sock,revbuffer,sizeof(revbuffer));
3.5 关闭网络连接
close(serv_sock);
tcp_client.cpp文件
#include <netinet/in.h>
#include <sys/types.h> //<sys/types.h>依赖头文件<netinet/in.h>
#include <sys/socket.h> //<sys/socket.h>依赖头文件<sys/types.h>
#include <arpa/inet.h> //inet_addr()的头文件
#include <unistd.h> //socklen_t的头文件
#include <iostream>
#include <string.h>
int main()
{
//1. 创建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == serv_sock)
{
std::cout<<"socket() 失败"<<std::endl;
return -1;
}
//2 设置要连接的对方的IP地址和端口等属性
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr)); //每个字节都用0填充
serv_addr.sin_family = AF_INET; //使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("192.168.0.109"); //服务端的IP地址
serv_addr.sin_port = htons(1886); //服务端的端口号
//发送连接请求
int res = connect(serv_sock ,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(res==-1)
{
std::cout<<"connect()失败"<<std::endl;
return -1;
}
std::cout<<"已连接服务端"<<std::endl;
//收发数据,每次均需指定地址信息
char recvbuf[1024];
int read_len;
read_len = read(serv_sock,recvbuf,1024);
std::cout<<recvbuf<<std::endl;
//关闭网络连接
close(serv_sock);
return 0;
}
4 编译及运行
Makefile文件:
all:Client Server
@echo ""
@echo "Start compiling"
@echo ""
Client:
@g++ -o Client tcp_client.cpp
Server:
@g++ -o Server tcp_server.cpp
clean:
-rm Server Client
make:
运行效果: