Linux Socket 通信:简单的socket通信

创建通信端点:

#include <sys/socket.h>
int socket(int domain, int type, int protocol);

第一个参数:domain参数指定通信域,这将选择将用于通信的协议系列,都被定义在<sys/socket.h>中,这里我们使用AF_INET协议,代表以ipv4方式通信
第二个参数:套接字具有指示的类型,该类型指定通信语义,这里我们使用SOCK_STREAM,意思是提供顺序的,可靠的,双向的,基于连接的字节流
第三个参数:该协议指定要与套接字一起使用的特定协议,一般情况下,在一个协议系列中只有一个协议支持一个特殊的套接子类型,所以一般设为0

返回值:成功返回文件描述符,失败返回-1

将地址绑定到套接字:

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

第一个参数:套接字描述符
第二个参数:分配给套接字描述符的地址
第三个参数:地址长度

返回值:成功返回0,失败返回-1

监听套接字上的连接:
listen将sockfd所引用的套接字标记为被动套接字,即,该套接字将用于使用accept接受传入的连接请求。

#include <sys/socket.h>
int listen(int sockfd, int backlog);

第一个参数:套接字描述符
第二个参数:backlog参数定义sockfd的未连接队列可以增长的最大长度

返回值:成功返回0,失败返回-1

接受套接字上的连接:
accept系统调用与基于连接的套接字类型(SOCK_STREAM,SOCK_SEQPACKET)一起使用。

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

第一个参数:套接字描述符
第二个参数:客户端结构体对象的指针
第三个参数:客户端结构体对象的大小

返回值:成功时,这些系统调用将返回非负整数,该整数是已接受套接字的描述符,失败返回-1

构建服务器端代码:

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>

using namespace std;

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

	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;

	char message[] = "Hello World";

	if (argc != 2) {
		cout << "Usage : " << argv[0] << " <port> " << endl;
		return -1;
	}

	serv_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (serv_sock == -1){
		cout << "Create server socket failed ..." << endl;
		return -1;
	}

	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]));

	int ret = bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	if (ret == -1) {
		cout << "bind failed ..." << endl;
		return -1;
	}

	ret = listen(serv_sock, 5);
	if (ret == -1) {
		cout << "listen failed ..." << endl;
		return -1;
	}

	socklen_t clnt_addr_size = sizeof(clnt_addr);
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
	if (clnt_sock == -1) {
		cout << "accept failed ..." << endl;
		return -1;
	}

	write(clnt_sock, message, sizeof(message));
	close(clnt_sock);
	close(serv_sock);
	return 0;
}

客户端发送连接请求:
connect系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址。

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

第一个参数:套接字描述符
第二个参数:sockaddr_in 结构体对象指针
第三个参数:sockaddr_in 结构体对象大小

返回值:成功返回0,失败返回-1;

构建客户端代码:

#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>

using namespace std;

int main(int argc, char* argv[]) {
	struct sockaddr_in serv_addr;
	char message[30];
	int str_len;

	if (argc != 3) {
		cout << "Usage : " << argv[0] << " <IP> <port>" << endl;
		return -1;
	}
	
	int clnt_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (clnt_sock == -1){
		cout << "Create client socket failed ..." << endl;
		return -1;
	}

	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]));

	socklen_t serv_addr_len = sizeof(serv_addr);
	int ret = connect(clnt_sock, (struct sockaddr*)&serv_addr, serv_addr_len);
	if (ret == -1) {
		cout << "connect failed ..." << endl;
		return -1;
	}

	str_len = read(clnt_sock, message, sizeof(message) - 1);
	if (str_len == -1) {
		cout << "read failed ..." << endl;
		return -1;
	}

	cout << "message from server: " << message << endl;
	close(clnt_sock);
	return 0;
}

创建套接字并不能决定那个是服务器端,那个是客户端。如果紧接着执行bind、listen函数,将成为服务器套接字,如果调用connect函数,将成为客户端套接字。

客户端通过调用connect函数向服务器发送链接请求。

服务器端调用accept函数受理连接请求,如果在没有连接的情况下调用该函数,则不会返回,直到有连接请求为止。

服务器的write函数向套接字写入消息,客户端的read函数从套接字读取信息。

执行过程:

在命令行分别将服务器端代码和客户端代码编译,生成两个可执行文件,并在两个终端分别执行可执行文件

g++ client.cpp -o client
g++ server.cpp -o server
./server 9190 # 服务器端命令
./client 127.0.0.1 9190 # 客户端命令
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值