c++ 网络编程 之socket

12 篇文章 0 订阅
10 篇文章 1 订阅

网络应用依赖于很多系统研究中已经学习过的概念,例如,进程、信号、字节顺序、存储器映射以及动态存储分配,接下来的文章主要内容为理解基本的客户端-服务器编程模型,实现编写一个web服务器。

客户端 - 服务器编程模型

俗称的cs架构,基本每个网络都是基于客户端-服务器模型(服务器管理资源,为客户端提供服务):

  1. 客户端向服务器发送一个请求,发起一个事务
  2. 服务器接受到请求后,解析它,并操作它的资源;
  3. 服务器给客户端发送一个响应,等待下一个请求;
  4. 客户端收到响应并处理它;

这里的事务 不是常说的原子性概念上的事务,只是描述一次请求响应的执行步骤

那么实现web服务器的具体流程就可描述为:客户端向服务器请求一个html文件,服务器响应请求后就读取一个磁盘文件,服务器将文件发送回客户端,客户端处理响应并由浏览器展示文件

网络 socket编程

客户端和服务器之间通过计算机网络的硬件和软件资源来通信,网络这部分内容主要讲解套接字(socket)。
一个套接字是连接的一个端点,一个连接即由两端的套接字地址唯一确定,形成套接字对(cliaddr:cliport, servaddr:servport)。
在这里插入图片描述

从unix程序的角度来看,套接字就是一个有相应描述符的打开文件。因此定义了函数open_clientfd封装了客户端socket的创建,定义了函数open_listentfd封装服务器socket的创建。

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

客户端和服务器使用socket函数来创建一个套接字描述符:

clientfd = socket(AF_INET, SOCK_STREAM, 0);

AF_INET表明使用因特网,SOCK_STREAM表示因特网连接的一个端点,返回:若成功则为非负描述符(表示获取到内核分配资源),出错则为-1. 该描述符仅是部分打开的,还不能读写

  1. connect 函数
#include <sys/socket.h>
int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);

客户端通过connect来建议和服务器的连接,addrlen是sizeof(sockaddr_in) = 16字节。
connect会阻塞直到连接建立或者错误,如果成功,sockfd就准备好可以读写,并且得到的连接是由套接字对(x:y serv_addr.sin_addr:serv_addr.sin_port)刻画的,其中 x为客户端ip地址,y表示临时端口,由此确认客户端主机上的客户端进程
补充:

struct sockadd {
	unsigned short	sa_family;  //protocol family
	char			sa_data[14];//address data
};

struct sockaddr_in {
	unsigned	short	sin_family;	//address family (always AF_INET)
	unsigned	short	sin_port;	//port number in network	byte	order
	struct	in_addr		sin_addr;	//ip address in network byte order
	unsigned	char	sin_zero[8];//pad to sizeof(struct sockaddr)
};
  1. open_clientfd函数
    将socket和connect函数封装起来调用会更方便
typedef struct sockaddr SA;

int open_clientfd(char *hostname, int port) {
	int clientfd;
	struct hostent *hp;
	struct sockaddr_in serveraddr;

	if ((clientfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
		return -1;
	}

	if ( (hp = gethostbyname(hostname)) == NULL ) {
		return -2;
	}

	//非标准c 可以用memset代替 #define bzero(b, len) (memset((b), '\0', (len)))
	bzero((char*) &serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	//同memcpy, 但注意的是memcpy(dest, src, lien), 目的位置放置参数1, 而bcopy相反
	bcopy((char*) hp->h_addr_list[0], (char*)&serveraddr.sin_addr.s_addr, hp->h_length);
	//网络字节顺序为大端法 数据低位放置内存高地址
	serveraddr.sin_port = htons(port);

	if(connect(clientfd, (SA*) &serveraddr, sizeof(serveraddr)) < 0) {
		return -1;
	}

	return clientfd;
}

通过gethostbyname检索服务器的DNS主机条目,并拷贝其第一个ip地址(已经是网络字节顺序),初始化服务器套接字地址结构后发起请求

以下为服务器端socket部分
4. bind函数

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

bind函数告诉内核my_addr中的服务器套接字地址和套接字描述符sockfd联系起来

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

listen将sockfd从一个主动套接字转化为监听套接字。backlog参数暗示了内核在开始拒绝连接请求之前,应该放入队列中等待的未完成连接请求的数量,属于tcp/ip协议的理解,通常设置 1024的值。

  1. open_listendfd函数
int open_listenfd(int port) {
	int listenfd, optval=1;
	struct sockaddr_in serveraddr;
	
	if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		return -1;
	}

	//eliminates "Address already in use" error from bind
	//默认地, 一个重启的服务器将在大约30秒内拒绝客户端的连接请求
	if ( setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&optval, sizeof(int)) < 0 ) 
		return -1;
	 
	 //非标准c 可以用memset代替 #define bzero(b, len) (memset((b), '\0', (len)))
	bzero((char*) &serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//网络字节顺序为大端法 数据低位放置内存高地址
	serveraddr.sin_port = htons((unsigned short)port);

	if(bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
		return -1;

	if (listen(listenfd, LISTENQ) < 0)
		return -1;

	return listentfd;
}

设置INADDR_ANY 通配符地址告诉内核接受来自任何IP地址的请求

  1. accept函数
int accept(int listenfd, struct sockaddr *addr, int *addrlen);

accept等待来自客户端的连接请求到达监听描述符listenfd,然后再addr中填写客户端的套接字地址, 并返回一个已连接描述符。服务器每次接受连接请求时都会创建一次连接描述符,用于表示客户端跟服务器之间连接的一次连接。这个概念将在建立并发服务器时讲述。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Socket网络编程是一种在计算机网络中进行数据交互的编程方式。通过使用Socket,我们可以在不同的计算机之间建立网络连接并进行数据传输。 在C语言中,我们可以使用标准库中的socket函数来创建一个Socket。首先,我们需要使用socket函数来创建一个Socket套接字,指定协议和类型。然后,使用bind函数将Socket与一个本地地址绑定,通常是一个IP地址和一个端口号。接着,使用listen函数启动Socket的监听模式,等待其他计算机发起连接请求。 一旦有其他计算机发起连接请求,我们可以使用accept函数来接受连接,并返回一个新的Socket文件描述符,这个新的Socket可以用于与对方进行数据交互。在这之后,我们可以使用send和recv函数来发送和接收数据。 当数据发送完毕或接收完毕后,我们可以使用close函数关闭Socket,释放资源。在进行Socket网络编程时,我们还可以使用select函数来实现多路复用,同时监听多个Socket,提高程序的效率。 在Socket网络编程中,还可以使用一些其他的函数来设置Socket的各种属性,例如设置Socket为非阻塞模式,设置等待时间等。 总之,Socket网络编程提供了一个方便的方式来进行网络通信。通过使用Socket函数及其相关函数,我们可以在C语言中轻松实现网络编程,实现不同计算机之间的数据交互。 ### 回答2: c socket网络编程是一种用C语言编写的网络编程技术,它允许计算机之间通过网络进行通信和数据交换。在C语言中,socket函数库提供了一种方便的方式来创建网络应用程序。 使用C socket网络编程,我们可以通过创建一个套接字(socket)来建立与其他计算机的连接。套接字可以视为两个应用程序之间的通信端口。一个应用程序可以充当服务器(server),等待其他应用程序的连接请求,并接受它们的连接。另一个应用程序可以充当客户端(client),向服务器发送连接请求,并与服务器建立连接。一旦连接建立,我们可以在客户端和服务器之间传递数据。 在进行C socket网络编程时,我们需要使用一些重要的函数,如socket、bind、listen、accept、connect和send/recv等。其中,socket函数用于创建一个套接字,bind函数用于将套接字与本地IP地址和端口绑定,listen函数用于在服务器端开始监听连接请求,accept函数用于接受客户端的连接请求,connect函数用于与服务器建立连接,send/recv函数用于在已经建立的连接上发送和接收数据。 C socket网络编程在实际应用中具有广泛的用途。它可以用于开发各种类型的网络应用程序,如网络聊天室、网络游戏、文件传输、远程控制等。通过使用C socket网络编程技术,我们可以轻松地实现不同计算机之间的通信和数据交换,为用户提供更好的网络体验。 ### 回答3: C语言的socket网络编程是指利用socket库函数,通过TCP/IP协议或UDP协议在网络上进行数据通信的一种编程方式。 在C语言中,可以使用socket()函数创建一个套接字,该函数返回一个整数值作为套接字的标识符。创建套接字后,可以使用bind()函数将套接字与本地的IP地址和端口号绑定起来。 对于服务器端程序,可以使用listen()函数设置套接字为监听状态,然后通过accept()函数接受客户端的连接请求。 对于客户端程序,可以使用connect()函数连接到服务器端的套接字。连接成功后,客户端可以使用send()函数发送数据给服务器端,也可以使用recv()函数接收服务器端发送过来的数据。 在网络编程中,需要注意错误处理。例如,当创建套接字或者连接失败时,需要使用perror()函数输出错误信息,并且使用close()函数关闭套接字。此外,还需要使用htons()和htonl()函数将主机字节序转换为网络字节序,以及使用ntohs()和ntohl()函数将网络字节序转换为主机字节序。 socket网络编程还可以使用多线程或多进程实现并发处理,可以同时处理多个连接请求,提高服务器的并发性能。 总之,C语言的socket网络编程是一种强大的工具,用于在网络上进行数据通信。它可以使程序与程序之间实现数据的传输和通信,方便地实现分布式系统、网络游戏、即时通信等应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值