#include<iostream>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
//错误处理宏
#define error_handling(message){std::cerr<<message<<"error!"<< strerror(errno) <<std::endl;\
exit(1);}
int main(int argc,char*argv[]){
int serv_sock,clnt_sock;
//零构造地址信息
struct sockaddr_in serv_addr{};
struct sockaddr_in clnt_addr{};
socklen_t clnt_addr_size;//地址信息大小
std::string message="hello,world!";//要传输的数据
//错误输入处理
if(argc!=2){
std::cout<<"Usage:"<<argv[0]<<"<port>"<<std::endl;
exit(1);
}
//创建TCP套接字
serv_sock=socket(PF_INET,SOCK_STREAM,0);
if(serv_sock==-1)error_handling("socket");
//设置地址信息
serv_addr.sin_family=PF_INET;
//INADDR_ANY宏定义为 0(uint32_t),表示"任意 IP 地址"(0.0.0.0)。用于服务器绑定时,监听所有网络接口
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//将主机字节序的 32 位无符号长整数(uint32_t)转换为网络字节序
serv_addr.sin_port=htons(atoi(argv[1])/*将字符串转换为整数*/);
//绑定地址信息
if(bind(serv_sock,(const sockaddr*)&serv_addr,sizeof(serv_addr))==-1)error_handling("bind");
//监听客户端
if(listen(serv_sock,5)==-1)error_handling("listen");
clnt_addr_size=sizeof(clnt_addr);
//建立连接并生成客户端套接字
clnt_sock=accept(serv_sock,(sockaddr*)&clnt_addr,&clnt_addr_size);
if(clnt_sock==-1)error_handling("accept");
//写入数据
write(clnt_sock,(void*)message.c_str(),message.size());
//断开连接
close(clnt_sock);
//关闭服务器端套接字
close(serv_sock);
return 0;
}
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
//错误处理宏
#define error_handling(message){std::cerr<<message<<"error!"<< strerror(errno) <<std::endl;\
exit(1);}
int main(int argc,char*argv[]){
//创建文件描述符
int sock;
//零构造地址信息
struct sockaddr_in serv_addr{};
//缓冲区
std::string message;
int str_len;//记录接收到的字节数
//错误输入处理
if(argc!=3){
std::cout<<"Usage:"<<argv[0]<<"<IP><port>"<<std::endl;
exit(1);
}
//创建TCP套接字
sock=socket(PF_INET,SOCK_STREAM,0);
if(sock==-1)error_handling("socket");
//设置地址信息
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);//将点分十进制 IP 字符串(如 "127.0.0.1")转换为网络字节序的 32 位整数(in_addr_t,通常 uint32_t)
serv_addr.sin_family=PF_INET;
serv_addr.sin_port=htons(atoi(argv[2]));//将主机字节序的 16 位无符号短整数(uint16_t)转换为网络字节序(大端序)
//连接套接字
if(connect(sock,(const sockaddr*)&serv_addr,sizeof(serv_addr))==-1)error_handling("connect");
//读取信息
message.resize(30); // 调整大小
//读取数据 read读取时会阻塞当前线程 属于同步阻塞的IO函数
str_len=read(sock,&message[0],message.size());
if(str_len==-1)error_handling("read");
message.resize(str_len);// 截断到实际长度,避免打印垃圾
//打印信息
std::cout<<"message from server:"<<message<<std::endl;
close(sock);//关闭套接字
return 0;
}
这是一个简单的单连接 TCP echo 示例(服务器发送固定消息,客户端接收打印)。流程基于标准 socket API:
- 服务器端启动:
-
- 创建监听套接字 (
serv_sock = socket(PF_INET, SOCK_STREAM, 0))。 - 设置地址:
family=PF_INET, addr=htonl(INADDR_ANY)(任意 IP),port=htons(atoi(argv[1]))(指定端口)。 bind()绑定地址,listen() 进入监听(队列大小 5)。accept()阻塞等待客户端连接,生成 clnt_sock(已连接套接字)。- 通过
clnt_sock write()发送消息 ("hello,world!")。 close(clnt_sock)和close(serv_sock)断开。
- 创建监听套接字 (
- 客户端启动(在服务器监听后):
-
- 创建套接字 (
sock = socket(PF_INET, SOCK_STREAM, 0))。 - 设置服务器地址:
family=PF_INET, addr=inet_addr(argv[1]), port=htons(atoi(argv[2]))。 connect()发起连接(三次握手)。read()阻塞读取数据到缓冲 (message),打印。close(sock)断开(四次挥手)。
- 创建套接字 (
- 底层机制:
-
- TCP 确保可靠传输(重传、顺序)。
- 字节序转换 (htons/htonl) 标准化为大端序。
- 数据从应用层 → TCP 层 → IP 层 → 网卡传输。
注:网络字节序是大端序,也就是高地址在高位,低地址在低位(高位在前低位在后)小端序与其相反,有些系统可能采用小端序,为在网络上统一,网络字节序统一使用大端序