Socket TCP编程

本文详细介绍了在Ubuntu系统中如何使用TCP协议通过套接字进行服务端和客户端的通信。首先,讲述了获取IP地址的方法,然后逐步解析了创建套接字、绑定IP和端口、开启监听、接受连接、收发数据以及关闭连接的步骤,分别展示了服务端和客户端的代码实现。
摘要由CSDN通过智能技术生成

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:
在这里插入图片描述

运行效果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值