Linux——socket(TCP)

服务器端和客户端,头文件和细节函数等,写下备忘。

server 阻塞版本如下:

<span style="font-family:KaiTi_GB2312;font-size:14px;"><strong>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]	){
	int server_socket = socket( AF_INET, SOCK_STREAM, 0);
	if(server_socket < 0) {
		perror("socket:");
		exit(-1);
	}

	struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("208.208.103.13");
    server_addr.sin_port = htons(2288);

	if( bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) )
	{
		perror("bind:");
		exit(-1);
	}
	
	if( listen(server_socket, 100) ){
		perror("listen");
		exit(-1);
	}
	printf("listen success!\n");
	struct sockaddr_in client_addr;
	socklen_t  addrlen = sizeof(client_addr);
	int new_client_fd = accept(server_socket, (struct sockaddr*)&client_addr, &addrlen);
	printf("new client connect!:%s\n", inet_ntoa( client_addr.sin_addr) );
	
	char buffer[1024];
	while(1){
		int iRet = read (new_client_fd, buffer, sizeof(buffer));	 
		if(0 > iRet){
			perror("read:"); exit(-1);
		}
		printf("read:%s\n", buffer);
	
		memset(buffer, 0, sizeof(buffer));
		strcpy(buffer, "server");	
		iRet = write (new_client_fd, buffer, strlen(buffer));
		if(0 > iRet){
			perror("write:"); exit(-1);
		}
		printf("write:%s\n", buffer);
	}
	close(server_socket);
	return 0;
}</strong></span>

server 非阻塞select版本如下:

<span style="font-family:KaiTi_GB2312;font-size:14px;"><strong>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]	){
	int server_socket = socket( AF_INET, SOCK_STREAM, 0);
	if(server_socket < 0) {
		perror("socket:");
		exit(-1);
	}

	struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("208.208.103.13");
    server_addr.sin_port = htons(2288);

	if( bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) )
	{
		perror("bind:");
		exit(-1);
	}
	
	if( listen(server_socket, 100) ){
		perror("listen");
		exit(-1);
	}
	printf("listen success!\n");
	struct sockaddr_in client_addr;
	socklen_t  addrlen = sizeof(client_addr);
	int new_client_fd = accept(server_socket, (struct sockaddr*)&client_addr, &addrlen);
	printf("new client connect!:%s\n", inet_ntoa( client_addr.sin_addr) );
	
	int iRet;
	char buffer[1024] = {};
	fd_set fread;
	while(1){
		FD_ZERO(&fread);
		FD_ZERO(&fwrite);
		FD_SET (new_client_fd, &fread);
		
		select(new_client_fd+1, &fread, NULL, NULL, 0);
		if(FD_ISSET(new_client_fd, &fread)) {
			iRet = read (new_client_fd, buffer, sizeof(buffer));	 
			if(0 > iRet){
				perror("read:"); exit(-1);
			}
			printf("read:%s\n", buffer);
		}
	}   
	close(server_socket);
	return 0;
}</strong></span>
server 非阻塞epoll版本如下:
<span style="font-family:KaiTi_GB2312;font-size:14px;"><strong>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

typedef void (*readClt) (void);

int new_client_fd;
void readClient(void){
	char buffer[1024] = {};
	int iRet = read (new_client_fd, buffer, sizeof(buffer));	 
	if(0 > iRet){
		perror("read:"); exit(-1);
	}
	printf("read:%s\n", buffer);
}

int main(int argc, char* argv[]	){
	int server_socket = socket( AF_INET, SOCK_STREAM, 0);
	if(server_socket < 0) {
		perror("socket:");
		exit(-1);
	}

	struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("208.208.103.13");
    server_addr.sin_port = htons(2288);

	if( bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) )
	{
		perror("bind:");
		exit(-1);
	}
	
	if( listen(server_socket, 100) ){
		perror("listen");
		exit(-1);
	}
	printf("listen success!\n");
	struct sockaddr_in client_addr;
	socklen_t  addrlen = sizeof(client_addr);
	new_client_fd = accept(server_socket, (struct sockaddr*)&client_addr, &addrlen);
	printf("new client connect!:%s\n", inet_ntoa( client_addr.sin_addr) );
	
	struct epoll_event stEvent;
	memset(&stEvent, 0, sizeof(stEvent));
    stEvent.events   = EPOLLIN;  /* 文件描述符可读 */
    stEvent.data.ptr = (void*)readClient; /* 事件私有数据:此处保存回调函数的指针 */
	int epfd = epoll_create (128);
	epoll_ctl( epfd, EPOLL_CTL_ADD, new_client_fd, &stEvent);

	while(1){
		struct epoll_event stEvent;
		int iRet = epoll_wait ( epfd, &stEvent, 1, 2000);
		if (iRet < 0 ) {
			printf("Error:epoll_wait!\n");
		}
		((readClt)stEvent.data.ptr)(); /* 调用回调函数 */
	}   
	close(server_socket);
	return 0;
}</strong></span>

client 如下:

<span style="font-family:KaiTi_GB2312;font-size:14px;"><strong>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]	){
	int client_socket = socket( AF_INET, SOCK_STREAM, 0);
	if(client_socket < 0) {
		perror("socket:");
		exit(-1);
	}

	struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("208.208.103.13");
    server_addr.sin_port = htons(2288);
	socklen_t   server_addr_length = sizeof(server_addr);    
    if( connect (client_socket, (struct sockaddr*)&server_addr, server_addr_length) ){
		perror("connect:");
		exit(-1);
	}
	printf("connect success!\n");

	char buffer[1024] ;
	while(1) {
		strcpy(buffer, "client");
		int iRet = write (client_socket, buffer, strlen(buffer));
	    if(0 > iRet){
			perror("write:"); exit(-1);
		}
		printf("write:%s\n", buffer);
		sleep(1);

		memset(buffer, 0, sizeof(buffer));
		iRet = read  (client_socket, buffer, sizeof(buffer));	 
		if(0 > iRet){
			perror("read:"); exit(-1);
		}
		printf("read:%s\n", buffer);

		sleep(1);
	}
	close(client_socket);
	return 0;
}</strong></span>

》》epoll知识点《《

epoll 相比于 select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。并且,在 linux/posix_types.h 头文件有这样的声明: #define __FD_SETSIZE 1024 表示select最多同时监听1024个fd,当然,可以通过修改头文件再重编译内核来扩大这个数目,但这似乎并不治本。

=====================
epoll的接口非常简单,一共就三个函数:
1、 int epoll_create(int size); 返回一个 epoll的句柄,size 内核监听的数目。当创建好epoll句柄后,它就是会占用一个fd值,在linux下查看/proc/进程id/fd/,能够看到,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。

@epfd 是epoll的句柄,即epoll_create()的返回值;

@op 表示动作,用三个宏来表示:
 EPOLL_CTL_ADD:注册新的fd到epfd中;
 EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
 EPOLL_CTL_DEL:从epfd中删除一个fd; 

@fd 是需要监听的fd;

@event是告诉内核需要监听什么事;

struct epoll_event 结构如下:
  typedef union epoll_data { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t;
  struct epoll_event { _uint32_t events; epoll_data_t data; };
events 可以是以下几个宏的集合:
 EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
 EPOLLOUT:表示对应的文件描述符可以写;
 EPOLLPRI:表示对应的文件描述符有紧急的数据可读;
 EPOLLERR:表示对应的文件描述符发生错误;
 EPOLLHUP:表示对应的文件描述符被挂断;
 EPOLLET:将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的;

 EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。

3、int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 

等待事件的产生,类似于select()调用。

@events 用来从内核得到事件的集合;

@maxevents 告之内核该events有大小,maxevents的值不能大于创建epoll_create()时的size

@timeout 超时时间(毫秒,0会立即返回)

@RETURN:需要处理的事件数目,如返回0表示已超时。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值