Linux_networking_programing(Linux网络编程总结)

自我总结之Linux网络编程。

前言:

网络:TCP/IP模型:物理层、数据链路层、网络层、传输层
网络数据传输:以太网帧、IP报文、TCP/UDP报文

一、进程间通信(IPC):

匿名管道,命名管道,socketpair,信号,信号量,锁,文件锁,共享内存等

原理:在进程外的公共区域申请内存,然后双方通过某种方式去访问公共区域内存

分类:

1、小数据量通信:管道,socketpair

2、大数据量通信:共享内存

3、进程间同步:socketpair、管道、锁、文件锁、信号量

(一)匿名管道:

内核buffer大小(ubuntu64k),满后write阻塞,

read时,管道没有数据,阻塞等待。
read时,write段已经关闭,管道有数据就读,没有返回0表示结束
1、创建:pipe产生两个文件描述符表示管道两端(读写);
2、读写:read,有数据就读; 无数据写端关闭,返回0; 写端未关闭,阻塞
write:如果管道有空间,写数据,长度以来管道buffer的剩余空间,返回值为写入的长度
如果管道无空间,那么阻塞;
如果read端已关闭,那么产生一个SIGPIPE信号,程序终止。如果程序处理了SIGPIPE,
那么程序不会终止,write返回-1,错误码标记为EPIPE;
3、应用:单工:单方通信; 半双工:两个方向通信,同一时刻只能有一个方向通信; 全双工:同时两方通信

(二)命名管道:

可用于非亲缘关系的进程;

创建:mkfifo
打开读端:open(“管道文件名”, O_RDONLY); 如果此时没有其他进程打开写端,那么该open阻塞;
打开写端:open(“管道文件名”, O_WRONLY);

(三)socketpair:

和匿名管道类似,不过是全双工

创建:int fd[2];
  socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
(四)mmap时间共享内存
有亲缘关系的进程mmap共享:匿名映射;
无亲缘关系的进程mmap共享:内存文件;
使用shm_open打开共享内存文件,以/起头,中间不能有/
(五)文件锁
int fd = open("a");
ret = flock(fd, LOCK_SH|LOCK_NB);
flock(fd, LOCK_UN);

int fd = open("a");
flock(fd, LOCK_SH);
flock(fd, LOCK_UN);

int fd = open("a");
flock(fd, LOCK_EX);
flock(fd, LOCK_UN);
(六)锁:pthread_mutex_init


二、TCP套接字通信(TCP/IP协议):

基于流的面向连接的通信.

流程:服务器:创建socket,绑定地址bind,监听listen; 客户端:创建socket,发送链接请求connect
  接收连接请求accept 发送数据send
  接收数据recv
代码:server:
int main()
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9999);
	addr.sin_addr.s_addr = INADDR_ANY;


	bind(fd, (struct sockaddr*)&addr, sizeof(addr));
	listen(fd, 10);
	int newfd = accept(fd, NULL, NULL);

	char buf[1024];
	recv(newfd, buf, sizeof(buf), 0);


	printf("recv data:%s\n", buf);
	send(newfd, buf, strlen(buf)+1, 0);


	close(newfd);
	close(fd);
	}
	client:
	int main()
	{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9999);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	connect(fd, (struct sockaddr*)addr, sizeof(addr));

	send(fd, "hello", 6, 0);
	char buf[1024];
	recv(fd, buf, sizeof(buf), 0);
return 0;
}

套接字描述符:使用 int shutdown(int sockfd, int how); 关闭一个方向的通信
网络字节序:大端字节序

设置套接字选项:fcntl/
int len = 256;
setsockopt(sockfd, SOL_SOCKET,SO_RCVBUF,&len, sizeof(len));

关闭套接字:close,对端关闭,read/recv返回0,本端写,产生SIGPIPE,若忽略SIGPIPE,那么写返回-1,错误码EPIPE;

三、UDP套接字:基于报文的通信

创建socket: int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
绑定地址:同TCP
发送和接收: sendto, 如果UDP调用了connect,也可以使用send
广播和多播:
关闭socket:close
UDP的数据是基于报文的,客户端调用一次send,产生一个UDP报文,接收一次只能接收一个报文
MTU(1400);

四、通信服务模型:
使用多进程:每个客户端对应一个进程,资源消耗大(早期apache服务器)
使用多线程:每个客户端对应一个线程,资源消耗大(优化过的Apache)
&&多路IO复用技术:iocp(windows)
1、select(跨平台):在少量文件描述符集合中,效率高,只能监听最多1024文件描述符
2、epoll(linux):支持大规模网络服务,只支持linux
使用多路IO复用技术和线程池:两个线程,一个负责epoll_wait和accept,另外一个线程负责接收和处理数据;
支持大规模网络服务,并且支持高并发;
使用多进程并发和多路IO复用技术:多个进程同事监听一个端口,如果外部有链接,多个进程通过内核实现的竞争机制会有一个进程被唤醒
效率非常高,Nginx就是用这种方式
#libevent:
event_base:
evconnlistener:对应一个坚挺的服务器
event


流程:创建一个集合->往集合增加各种事件->给时间一些任务(监听或者读写任务)->给时间设定回调函数(当任务完成时,event可以通过回调函数通知上层)
while(1) //监听event_base,看哪个有事件
code:
void conn_eventcb(struct bufferevent*bev,short events, void * user_data)
{
	if(events & BEV_EVENT_EOF)
	else if(events & BEV_EVENT_ERROR)
	
	bufferevent_free(bev);
}
void conn_writecb(struct bufferevent*bev, void *user_data)
{
	struct evbuffer*output = bufferevent_get_output(bev);
	if(evbuffer_get_length(output) == 0) bufferevent_free(bev);
}
	
void listener_cb(struct evconnlistener*l, evutil_socket_t sock,//文件描述符
	struct sockaddr*addr, int socklen, void *ptr))
{
	struct event_base*base = ptr;
	struct bufferevent*bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
	if(bev == NULL)exit(0);
	buffervnt_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
	
	bufferevent_enble(bev, EV_WRITE);
	bufferevent_disable(bev, EV_READ);
	bufferevent_write(bev, "hello", 5); //异步IO

}

int main()
{
	struct event_base* base = event_base_new();
	if(base == NULL)
	return 0;
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(8899);
	addr.sin_addr.s_addr = INADDRY_ANY;
	struct evconnlistener *listener = evconnlistener_new_bind(base,
	listener_cb(callback),(void*)base(callback argument),
	LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE(opt),
	-1, (struct sockaddr*)&addr(listen addr), sizeof(addr));
	if(listener == NULL) return 0;

	event_base_dispatch(base); 

	return 0;
}


五、HTTP协议
通信模型:支持客户端/服务器模式,简单快速,灵活,短连接,无状态
HTTP服务器/web服务器:apache,nginx,iis(windows)
客户端:浏览器
curl命令:
HTTP请求:请求行,消息报头,请求正文
HTTP响应:状态行,消息报头,响应正文
&&libcurl:基本流程:初始化CURL环境,创建CURL对象,设置CURL,执行CURL

bool getUrl(char *filename)
{
	CURL *curl;
	CURLcode res;
	FILE* fp;
	if((fp = fopen(filename, "w")) == NULL)
	return false;
	struct curl_slist *headers = NULL;
	headers = curl_slist_append(headers, "Accept: Agent-007");
	curl = curl_easy_init();
	if(curl){
		curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:9999");
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
		curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
		curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp);
		res = curl_easy_perform(curl);
		if(res != 0){
		curl_slist_free_all(headers);
		curl_easy_cleanup(curl);
		}
		fclose(fp);
		return true;
	}
}

ssize_t curl_callback(char* data, int m, int n, void* ptr)
{
    // "abc def"
    // string str = data; // OK???  NO
    string& ret = *(string*)ptr;

    string str;
    std::copy(data, data+m*n, back_inserter(str));

    ret += str;

    return m*n;
}
bool postUrl(char *filename)
{
	CURL *curl;
	char* res = "curl test";
	curl = curl_easy_init();
	if(curl){
		curl_easy_setopt(curl,CURLOPT_POSTFIELDS, res);
		curl_easy_setopt(curl, CURLOPT_URL, "www.baidu.com");
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_callback);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret);
		//ssl
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);

		CURLcode code = curl_easy_perform(curl);

		curl_easy_cleanup(curl);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值