网络实践第一步

    渣渣嵌入式的程序狗学网络

    1)理论知识

      有个小心得,当FD_ISSET(fd)为真时,处理完fd后,记得FD_CLR(fd, pset)。原因是当有多条session链表时,可能需要将一个session从一条session链表移到另外一条session链表。二每条session链表的处理是有先后顺序的,防止一个session被处理2次,第二次会阻塞。

    注意了select的超时时间和set每次都需要重新设置,如果超时后,tv超时时间变成了0,不重新设置的话,超时时间为0,就相当于轮训了。

    2)实际操作,做项目,自己写测试程序

    今天我写了一个select的测试程序,放出来。希望还没开始学习网络编程的,自己也写一个测试程序,写得多了,就慢慢的入门了。

    理论知识:epoll最好,poll次之,select最垃圾。学习指定从最垃圾的开始。可以看看这些博客来补充一下自己的理论的知识https://blog.csdn.net/fdgyfghh/article/details/83926265

    实际操作:

server端示例:

#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h> 


struct Session{
    int fd;
    struct sockaddr_in addr;
    char data[1024];
    Session* next;
};

struct SessionHead{
	Session head;
	int fd;
	int linknum;
	int max_fd;
	int max_link;
};


static void ap_server_exit(void* ptr)
{
	printf ("ap_server_exit\n");
	SessionHead* stab  = (SessionHead*)ptr;
	if (!stab)
	{
		return;
	}
	
	int i = 0;
	Session* tmp = stab->head.next;
	Session* priv = &stab->head;
	Session* next;
	for ( ; tmp != NULL; tmp = next)
	{
		next = tmp->next;
		if (tmp->fd > 0)
		{
			close(tmp->fd);
			i++;
		}
		tmp->fd = 0;
		tmp->next  = NULL;
		free (tmp);
	}
	stab->head.next = NULL;	
	if (stab->fd > 0)
	{
		close (stab->fd);
	}
	stab->fd = 0;
	stab->max_fd = 0;
	stab->linknum = 0;
	stab->max_link = 0;
	
	printf ("close listen sockect, close the all(%d) client\n", i);
	return;
}


static void ap_init_seleteset(fd_set* set, SessionHead* stab)
{
	if(!stab|| !set)
	{
		return;
	}
	
	FD_ZERO(set);
	if (stab->fd > 0)
	{
		printf ("add listen sockect to set, fd=%d\n", stab->fd);
		FD_SET(stab->fd, set); 
	}
	
	Session* tmp = stab->head.next; 
	
	int max_fd = stab->fd;
	for ( ; tmp != NULL; tmp = tmp->next)
	{
		if (tmp->fd > 0)
		{
			printf ("add accept sockect to set, fd=%d\n", tmp->fd);
			FD_SET(tmp->fd, set);
		}
		
		if (tmp->fd > max_fd)
		{
			max_fd = tmp->fd;
		}
	}
	printf ("max fd=%d\n", max_fd);
	stab->max_fd  = max_fd;
	return;

}

void* ap_server_thread(void* argc)
{
	int fd = socket(AF_INET, SOCK_STREAM, 0);
	if (fd <= 0)
	{
		printf ("socket open err\n");
		return NULL;
	}
	
	sockaddr_in ser_addr;
	memset (&ser_addr, 0, sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(30084);
	ser_addr.sin_addr.s_addr = INADDR_ANY;

    int on = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR , &on, sizeof(on));
    if (ret < 0)
    {
        perror("setsockopt failed");
        return NULL;
    }


	ret = bind(fd, (sockaddr*)&ser_addr, sizeof(ser_addr));
	if (ret != 0)
	{
		printf ("bind err\n");
		return NULL;
	}
	
	ret = listen(fd, 20);
	if (ret != 0)
	{
		printf ("listen err\n");
		return NULL;
	}

	SessionHead stab;
	stab.head.next = NULL;
	stab.max_fd = fd;
	stab.max_link = 10;
	stab.fd = fd;
	Session* head = &stab.head;

	pthread_cleanup_push(ap_server_exit, &stab);
	
	fd_set rset;
	struct timeval tv;
	
	FD_ZERO(&rset);
	FD_SET(fd, &rset); 	
	while(1)
	{
		pthread_testcancel();
		ap_init_seleteset(&rset, &stab);
		tv.tv_sec = 20;
		tv.tv_usec = 0;
		ret = select(stab.max_fd+1, &rset, NULL, NULL, &tv);
		if (ret < 0)
		{
			perror("select error:");
			break;
		}
	
		else if (ret == 0)
		{
			continue;
		}
		else 
		{
			printf ("some socket read ready, num=%d\n", ret);
	
			/* session message */
			Session* tmp = head->next;
			Session* priv = head;  /* have entity head is good */
			for (; tmp != NULL; tmp=tmp->next)
			{
				if(!FD_ISSET(tmp->fd, &rset))
				{
					continue;
				}
				memset (tmp->data, 0, sizeof(tmp->data));
				int num = recv(tmp->fd, tmp->data, sizeof(tmp->data) - 1, 0);
				if (num <= 0)
				{
					printf ("a client leave\n");
					close (tmp->fd);
					tmp->fd = 0;
					priv->next = tmp->next;
					tmp->next = NULL;
					free (tmp);
				}
				else
				{
					printf ("recv data len=%d\n", num);
					printf ("recv data:%s\n", tmp->data);
					
					char rsp[64];
					memset (rsp, 0 , sizeof(rsp));
					snprintf (rsp, sizeof(rsp), "i am server,i recv data len=%d", num);
					num = send (tmp->fd, rsp, strlen(rsp), 0);
					printf("%s, and send len=%d\n", rsp, num);
	
					if (strstr (tmp->data, "finish"))
					{
						char* finish = "finish";
						num = send (tmp->fd, finish, strlen(finish), 0);
						printf ("recv a finish, send a finish.num=%d\n", num);
					}
				}
				priv = tmp;
			}
	
			if (FD_ISSET(fd, &rset))
			{
				printf ("a new connect occur\n");
	
				Session* ses = (Session*)calloc (1, sizeof(Session));
				
				socklen_t len = sizeof(ses->addr);
				ses->fd = accept(fd, (sockaddr*)&ses->addr, &len);
				if (ses->fd <= 0)
				{
					printf ("accept error");
				}
				else
				{	
					printf ("accept successful, fd=%d ip=%s, port=%d\n",
						   ses->fd,  inet_ntoa(ses->addr.sin_addr) , ntohs(ses->addr.sin_port)); 
	
					int i = 0;
					Session* tmp = head;
					Session* tail = head;
					for ( ; tmp != NULL; tmp= tmp->next)
					{
						tail = tmp;
						i++;
					}
					
					if ((i-1) > stab.max_link)
					{
						printf ("max session :10, i will close the new client\n");
						close(ses->fd);
						ses->fd = 0;
						free (ses);
						ses = NULL;
					}
					else
					{
						int enable = 1;
						setsockopt(ses->fd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
						tail->next = ses;
						printf ("add session successful\n");
					}
				}
			}	
		}
	}
	pthread_cleanup_pop(1);
	return NULL;
}



int main(int argc, char* argv[])
{
	pthread_t tid ;
	
	int ret = pthread_create(&tid, NULL, ap_server_thread, NULL);
	if (ret != 0)
	{
		printf("pthread create failed\n");
		return 0;
	}
	
	printf ("--------------sleep 60s------\n");
	sleep (60);
	
	pthread_cancel(tid);
	pthread_join(tid, NULL);
	return 0;
}

client的示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h> 

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

    if (argc != 4)
    {
        printf ("usage:%s ip  port  data\n", argv[0]);
        printf ("for example: %s 192.168.99.144 30084 helloword\n", argv[0]);
        return -1;
    }

    char* ip = argv[1];
    int port = atoi(argv[2]);
    char* data =  argv[3];


    printf ("ip:%s  port:%d  data:%s\n", ip, port, data);


    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd <= 0)
    {
        printf ("socket error\n");
        return -1;
    }

    struct sockaddr_in s_addr;

    memset(&s_addr, 0, sizeof(s_addr));
    s_addr.sin_family= AF_INET;
    s_addr.sin_port = htons(port);
    s_addr.sin_addr.s_addr = inet_addr(ip);

    int ret = connect (fd, (sockaddr*)&s_addr, sizeof(s_addr));
    if (ret != 0 )
    {
        perror("connect error");
        return -1;
    }

    //int enable = 1;
    //ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
    //printf ("setsockopt tcp nodelay %d\n",ret);

    int i;
    int num = 0;
    int sum = 0;
    for (i = 0; i < 5; i++)
    {
        num = send(fd, data, strlen(data), 0);
        if (num > 0)
        {
            sum += num;
        }
        printf ("send len=%d and real=%d  total=%d\n",
                strlen(data), num, sum);

    }
   
    char* finish = "finish";

    num = send(fd, finish, strlen(finish), 0);
    printf ("send a finish to server, num=%d\n", num);


    int recvnum = 0;

    char buf [1024];
    while (1)
    {
        
        recvnum = recv (fd, buf, sizeof(buf)-1, 0);
        buf[recvnum] = '\0';
        printf ("recv num recvnum=%d\n", recvnum);
        printf ("recv data=%s\n", buf);
       
        if (recvnum <= 0)
        {
            printf ("the connect is unreachable\n");
            break;
        }
        if (strstr(buf, "finish"))
        {
            printf ("recive a finish, exit\n");
            break;
        }
    }
    close (fd);
    return 0;
}

对于像我这样的渣比们,一定要学网络编程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值