1.Socket_Linux(Linux下C++ socket)

目录

1. Socket(实现TCP)

2. 相关函数

2.1. socket()

2.2. bind()

2.3. listen()

2.4. accept()

2.5. write()/read()

2.6. connect()

3. 代码

3.1. 服务端代码

3.2. 客户端代码



1. Socket(实现TCP)


2. 相关函数

2.1. socket()

    调用socket()创建套接字

int socket(int af, int type, int protocol);
//socket()成功时返回文件描述符,失败时返回-1
  •     af:套接字中使用的协议族(Protocol Family)信息

  •     type:套接字数据传输类型信息

  •     protocol:计算机间通信中使用的协议信息 

        协议族Protocol Family:

名称

协议族

PF_INET

IPv4互联网协议族

PF_INET6

IPv6互联网协议族

PF_LOCAL

本地通信的UNIX协议族

PF_PACKET

底层套接字的协议族

PF_IPX

IPX Novell协议族

        套接字类型Type套接字类型指的是套接字的数据传输方式,通过第二个参数传递,只有这样才能决定创建的套接字的传  输方式。

            套接字类型1:有保障面向连接的套接字(SOCK_STREAM)

            套接字类型2:无保障面向消息的套接字(SOCK_DGRAM)

        协议最终选择protocol:IPPROTO_TCP,IPPROTO_UDP

    应用

int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

2.2. bind()

    调用bind()函数分配IP地址和端口号

int bind (int sockfd, struct sockaddr * myaddr, socklen_t addrlen);
//成功返回0,失败返回-1
  • sockfd:要分配地址信息(IP地址和端口号)的套接字文件描述符
  • myaddr:存有地址信息的结构体变量地址值(struct sockaddr*)
  • addrlen:第二个结构体变量的长度sizeof(myaddr)

    地址信息结构体

struct sockaddr_in
{
    sa_family_t     sin_family;        //地址族(Address Family)
    uint16_t        sin_port;          //16位TCP/UDP端口号
    struct in_addr  sin_addr;          //32位IP地址
    char            sin_zero[8];       //不使用
};

//sin_family(AF_INET,AF_INET16,AF_LOCAL)
//AF_INET:IPv4网络协议使用的地址族
//AF_INET16:IPv6网络协议使用的地址族
//AF_LOCAL:本地通信中采用的UNIX协议的地址族

//sin_port:保存16位端口号
//sin_addr:保存32位IP地址信息


struct in_addr
{
    In_addr_t        s_addr;           //32位IPv4地址
};

    应用:

...
struct sockaddr_in serv_addr;
char * serv_port = "9000"
//创建套接字
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
//初始化地址信息
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(atoi(serv_port));
//分配地址信息
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
...

    补充:

    htons():host to network short int

    htonl():host to network long int

    atoi():把字符串转换成整型数


2.3. listen()

    调用listen()函数将套接字转换为可接收连接状态

int listen (int sockfd, int n);
//成功返回0,失败返回-1

    sockfd:希望进入等待请求状态的套接字文件描述符,传递的参数成为服务器端套接字(监听套接字)。

    n:连接请求等待队列(Queue)的长度,若为5,则队列长度为5,表示最多使5个连接请求进入队列

    应用:

listen(serv_sock, 5);

2.4. accept()

    调用accept()函数受理连接请求,如果没有连接请求的情况下调用该函数,则没有返回,直到有连接请求为止

int accept (int sockfd, struct sockaddr * addr,socklen_t * addrlen);
//成功时返回创建的套接字文件描述符,失败返回-1
  •     sockfd:服务器套接字的文件描述符
  •     addr:保存发起连接请求的客户端地址信息的变量地址值,调用函数后向传递来的地址变量地址填充客户端地址信息
  •     addrlen:第二个参数结构体addr的长度,但是存有长度的变量地址。函数调用后,改变量被填充为客户端地址长度 

    应用:

accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

2.5. write()/read()

    调用write()/read()函数进行数据传输

write (int fd, const void *__buf, size_t nbytes);
//成功时返回写入的字节数,失败返回-1
//fd:显示数据传输对象的文件描述符
//buf:保存要传输数据的缓冲地址池
//nbytes:要传输数据的字节数
read (int fd, void *__buf, size_t nbytes);
//成功时返回接收到的字节数(若遇到文件结尾返回0),失败返回-1
//fd:显示数据接收对象的文件描述符
//buf:要保存接收数据的缓冲地址值
//nbytes:要接收数据的字节数

2.6. connect()

   调用connect()函数向服务器发送连接请求

int connect (int sockfd,struct sockaddr* servaddr, socklen_t addrlen);
//成功返回0,失败返回-1
  •     sockfd:客户端套接字文件描述符
  •     servaddr:保存目标服务器地址信息的变量地址值
  •     addrlen:以字节为单位传递已传递给第二个结构体参数的地址变量长度 

    应用:

connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr);

3. 代码

3.1. 服务端代码

#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
	int serv_sock;
	int clnt_sock;

	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;
	string message = "Hello World!";
	if (argc != 2) {
		printf("Usage : %s <port>\n", argv[0]);
		exit(1);
	}
	//1.1. 调用socket()创建套接字
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1)
		cout << "socket() error" << endl;
	//地址初始化
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(atoi(argv[1]));
	//1.2. 调用bind()函数分配IP地址和端口号
	if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		cout << "bind() error" << endl;
	//1.3. 调用listen()函数将套接字转换为可接收连接状态
	if (listen(serv_sock, 5) == -1)
		cout << "listen() error" << endl;
	clnt_addr_size = sizeof(clnt_addr);
	//1.4. 调用accept()函数受理连接请求
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	if (clnt_sock == -1)
		cout << "accept() error" << endl;
	//1.5. 调用write()/read()函数进行数据传输
	write(clnt_sock,message.c_str(), sizeof(message));
	close(clnt_sock);
	close(serv_sock);
	return 0;
}

3.2. 客户端代码

#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	char message[30];
	int str_len = 0;
	int idx = 0, read_len = 0;
	if (argc != 3) {
		cout << "Usage : %s IP port" << argv[0] << endl;
		exit(1);
	}
	//2.1. 调用socket()创建套接字
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
		cout << "socket() error" << endl;
	//地址初始化
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]));
	//2.2.调用connect()函数向服务器发送连接请求
	if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		cout << "connect() error!" << endl;
	//2.3. 调用write()/read()函数进行数据传输
	while (read_len = read(sock, &message[idx++], 1))
	{
		if (read_len == -1)
			cout << "read() error!" << endl;

		str_len += read_len;
	}
	cout << "Message from server: " << message << endl;
	cout << "Function read call count: " << str_len << endl;
	close(sock);
	return 0;
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值