Linux C Socket编程原理及tcp, udp简单实例

tcp

http://www.cnblogs.com/xudong-bupt/archive/2013/12/29/3483059.html

http://blog.csdn.net/hguisu/article/details/7445768/


Linux C Socket编程原理及tcp, udp简单实例_第1张图片

函数层面的3次握手 连接

Linux C Socket编程原理及tcp, udp简单实例_第2张图片

函数层面的4次挥手

Linux C Socket编程原理及tcp, udp简单实例_第3张图片



redis 采用tcp协议,自己写个客户端,按照redis的数据格式协议发送数据

一个测试例子

client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFFER_SIZE 1024

/* read n bytes to a descrpiter */
ssize_t Readn(int fd,const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nread;
	const char *ptr;
	ptr = vptr;
	nleft = n;
	while (nleft > 0) 
	{
		if( (nread = read(fd, ptr, nleft)) < 0)
		{
			if( nread < 0)
				nread = 0;
			else
				return -1; // error
		}
		nleft -= nread;
		ptr += nread;
	}
	return n-nleft;	
}


/* write n bytes to a descrpiter */
ssize_t Writen(int fd,const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;
	ptr = vptr;
	nleft = n;
	while (nleft > 0) 
	{
		if( (nwritten = write(fd, ptr, nleft)) <= 0)
		{
			if( nwritten < 0)
				nwritten = 0;
			else
				return -1; // error
		}
		nleft = -nwritten;
		ptr += nwritten;
	}
	return n;	
}

ssize_t readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t n, rc;
	char c, *ptr;
	ptr = vptr;
	for(n = 1 ;n < maxlen; n++)
	{
		if( (rc = read(fd, &c, 1)) == 1)
		{
			*ptr++ = c;
			if(c == '\n')
				break;
		}else if( rc == 0) {
			*ptr = 0;
			return (n-1);
		}else{
			return -1;
		}
	}
	*ptr = 0;
	return n;
}

int main(int argc, char **argv)
{
	///定义sockfd
	int sock_cli = socket(AF_INET,SOCK_STREAM, 0);

	if (argc != 3)
    	{
       	 	printf("please inpurt ip and port\n");
        	exit(1);
    	}

	///定义sockaddr_in
	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));  ///服务器端口
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);  ///服务器ip

	///连接服务器,成功返回0,错误返回-1
	if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
	{
		perror("connect");
		exit(1);
	}
	printf("connect sucess!\n");

	char sendline[BUFFER_SIZE];
	char recvbuf[BUFFER_SIZE];
	// redis set 命令
	strcpy(sendline,"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n");
	
	send(sock_cli, sendline, strlen(sendline),0); ///发送
        
	//recv(sock_cli, recvbuf, sizeof(recvbuf),0); ///接收
	int n = readline(sock_cli, recvbuf,sizeof(recvbuf));

	printf("%d\n",n);
	printf("%s", recvbuf);
	
	close(sock_cli);	
	exit(0);
}

Makefile

.PHONY: build clean test

CC=gcc
HEADERS=-I.
DEBUG=-g -ggdb  
WALL=-Wall -W  
CFLAGS=$(WALL) $(DEBUG)  
L_CC=$(CC) $(CFLAGS) $(HEADERS)     

build:client

client:client.c
	$(L_CC) $< -o $@

clean:
	@-if [ -f client ]; then rm client; fi

test:
	./client 127.0.0.1 6379


Linux C Socket编程原理及tcp, udp简单实例_第4张图片


改进reids-cli,自己把字符串封装成要发送的数据(ubuntu14.04 32bit环境下,代码很渣,基本实现功能)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define BUFFER_SIZE 1024

#define MAX_PARA_NUMS      1024  
#define MAX_CHAR_EACH_PARA 1024  

char params[MAX_PARA_NUMS][MAX_CHAR_EACH_PARA];


int max(int a, int b)
{
	return a>b?a:b;
}


/** 
把带空格的input字符串 分割成几个不带空格的字符串 
例如: 
input = "ls /homg/ding" 
那么 
output[0] = "ls"  
output[1] = "/home/ding" 
 
函数返回output的数量 
*/  
int split(char* input, char output[MAX_PARA_NUMS][MAX_CHAR_EACH_PARA]) // 接收一个一个的参数)  
{  
    int counter = 0;  
  
    int len = strlen(input);  
    while(input[len-1] == ' ' || input[len-1] == '\n' )
	len --;
    int flag = 0 ;  
    int i, j = 0 ;  
    for(i = 0; i < len; i++)  
    {  
        if(input[i] == ' ') //当前字符是空格时,flag设为0 保存当前的字符串  
        {  
            if(j != 0 && counter > 0)  
            {  
                output[counter - 1][j] = '\0';  
            }  
            flag = 0;  
        }  
        else  
        {  
            if(flag == 0) // 新的字符串开始 bTemp设为 1  
            {  
                j = 0;  
                counter++;  
                flag = 1;  
            }  
          
            output[counter - 1][j] = input[i]; // 仍然是上一个str  
            j++;  
        }  
    }     
    return counter;   
}  


/* write n bytes to a descrpiter */
ssize_t Writen(int fd,const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;
	ptr = vptr;
	nleft = n;
	while (nleft > 0) 
	{
		if( (nwritten = write(fd, ptr, nleft)) <= 0)
		{
			if( nwritten < 0)
				nwritten = 0;
			else
				return -1; // error
		}
		nleft = -nwritten;
		ptr += nwritten;
	}
	return n;	
}

ssize_t readline(int fd, void *vptr, size_t maxlen)
{
	ssize_t n, rc;
	char c, *ptr;
	ptr = vptr;
	for(n = 1 ;n < maxlen; n++)
	{
		if( (rc = read(fd, &c, 1)) == 1)
		{
			*ptr++ = c;
			if(c == '\n')
				break;
		}else if( rc == 0) {
			*ptr = 0;
			return (n-1);
		}else{
			return -1;
		}
	}
	*ptr = 0;
	return n;
}


void num2charstar(int num, char strnum[])
{
	int n = num;
	int count = 0;
	while (num != 0)
	{
		num /= 10;
		count++;
	}
	
	int len = count + 1;
	while (n != 0)
	{
		int tmp = n % 10;
		n = n / 10;
		strnum[--count] = (char)(tmp + '0');
	}
	strnum[len] = '\0';
}

int redisstr(char send[], char s[MAX_PARA_NUMS][MAX_CHAR_EACH_PARA],int num,char numstr[])
{
	int nextpos = 0;

	strcpy(send + nextpos, "*");
	nextpos += 1;

	num2charstar(num, numstr);
	//printf("qian:%s\n",send);
	strcpy(send + nextpos, numstr);
	//memcpy(send+nextpos,numstr,strlen(numstr));	
	//printf("hou:%s\n",send);
	nextpos += strlen(numstr);

	strcpy(send + nextpos, "\r\n");
	nextpos += 2;

	int i;
	for (i = 0; i < num; i++){
		char* tmp = s[i];
		int len = strlen(tmp);
		//printf("--%d %s\n",len,tmp);
		strcpy(send + nextpos, "$");
		nextpos += 1;

		num2charstar(len, numstr);
		strcpy(send + nextpos, numstr);
		nextpos += strlen(numstr);

		strcpy(send + nextpos, "\r\n");
		nextpos += 2;

		strcpy(send + nextpos, tmp);
		nextpos += len;

		strcpy(send + nextpos, "\r\n");
		nextpos += 2;	
	}
	send[nextpos] = '\0';
	return nextpos;
}



void str_cli(FILE *fp, int sockfd)
{
	char sendline[BUFFER_SIZE], recvline[BUFFER_SIZE];
	int maxfdpl, stdineof;
	fd_set rset; // 描述符集

	stdineof = 0;	
	FD_ZERO(&rset); //清除文件描述符集fdset中的所有位(既把所有位都设置为0)
	for(; ;){
		if(stdineof == 0)	
			FD_SET(fileno(fp), &rset);//取出文件描述符,并打开相应在文件描述位
		FD_SET(sockfd, &rset);
		maxfdpl = max(fileno(fp), sockfd) + 1; //等待的描述集
		// select 如果有描述符 则返回起数目,若超时,返回0 ,出错返回-1
		select(maxfdpl, &rset, NULL, NULL, NULL);
		if(FD_ISSET(sockfd, &rset)){ //判断sockfd是否在描述集中
			if(readline(sockfd, recvline, BUFFER_SIZE) == 0)
			{
				if(stdineof == 1)
					return ; // 正常终止
				else					
				{
					perror("server terminated");
					exit(0);
				}	
			}
			fputs(recvline,stdout);	
		}
		int n;
		if(FD_ISSET(fileno(fp), &rset)){ // 判断fp是否在描述集中
			if( (n = readline(fileno(fp), sendline, BUFFER_SIZE)) == 0)
			{
				stdineof = 1;
				shutdown(sockfd,SHUT_WR);
				FD_CLR(fileno(fp), &rset);
				continue;			
			}

			int sendlen = strlen(sendline);
			sendline[sendlen] = '\0';
			//printf("----%d\n",sendlen);
			int nums = split(sendline, params);

			char send2[BUFFER_SIZE];
			char numstr[100];
			int send2len = redisstr(send2,params,nums,numstr);
			//printf("长度是:%d\n",send2len);
			Writen(sockfd, send2, send2len);	

			//Writen(sockfd, sendline, strlen(sendline));	
		}
	}
}

int main(int argc, char **argv)
{
	///定义sockfd
	int sock_cli = socket(AF_INET,SOCK_STREAM, 0);

	if (argc != 3)
    	{
       	 	printf("please inpurt ip and port\n");
        	exit(1);
    	}

	///定义sockaddr_in
	struct sockaddr_in servaddr;
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));  ///服务器端口
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);  ///服务器ip

	///连接服务器,成功返回0,错误返回-1
	if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
	{
		perror("connect");
		exit(1);
	}
	printf("connect sucess!\n");

	// redis set 命令
	//strcpy(sendline,"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n");
	
	str_cli(stdin,sock_cli); //回射客户端的程序 	
       	
	exit(0);
}


自己执行简单的get,set命令


Linux C Socket编程原理及tcp, udp简单实例_第5张图片


udp

http://www.cnblogs.com/uvsjoh/archive/2013/01/01/2841764.html


Linux C Socket编程原理及tcp, udp简单实例_第6张图片


UDP编写的常用协议应用程序有:DNS(域名系统),NFS(网络文件系统) 和 SNMP(简单网络管理协议)

----------------------------------

Makefile

.PHONY: build clean

CC=gcc
HEADERS=-I.
DEBUG=-g -ggdb  
WALL=-Wall -W  
CFLAGS=$(WALL) $(DEBUG)  
L_CC=$(CC) $(CFLAGS) $(HEADERS)     

build:server client

server:server.c
	$(L_CC) $< -o $@

client:client.c
	$(L_CC) $< -o $@

clean:
	@-if [ -f server ]; then rm server; fi
	@-if [ -f client ]; then rm client; fi


server.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main(int argc, char **argv)
{
    if (argc != 2)
    {
        printf("Usage: %s port\n", argv[0]);
        exit(1);
    }
    printf("Welcome! This is a UDP server, I can only received message from client and reply with same message\n");
    
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[1]));
    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    int sock;
    if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) // 创建sccket
    {
        perror("socket");
        exit(1);
    }
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) //绑定地址
    {
        perror("bind");
        exit(1);
    }
    char buff[512];
    struct sockaddr_in clientAddr;
    int n;
    int len = sizeof(clientAddr);
    while (1)
    {
	// 一直阻塞到收到来自客户端的数据
        n = recvfrom(sock, buff, 511, 0, (struct sockaddr*)&clientAddr, &len);
        if (n>0)
        {
            buff[n] = 0;
            printf("%s %u says: %s\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port), buff);
            // 向客户端发送数据
	    n = sendto(sock, buff, n, 0, (struct sockaddr *)&clientAddr, sizeof(clientAddr));
            if (n < 0)
            {
                perror("sendto");
                break;
            }
        }
        else
        {
            perror("recv");
            break;
        }
    }
    return 0;
}

client.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
    if (argc != 3)
    {
        printf("Usage: %s ip port", argv[0]);
        exit(1);
    }
    printf("This is a UDP client\n");
    struct sockaddr_in addr;
    int sock;

    if ( (sock=socket(AF_INET, SOCK_DGRAM, 0)) <0) // 创建socket
    {
        perror("socket");
        exit(1);
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    if (addr.sin_addr.s_addr == INADDR_NONE)
    {
        printf("Incorrect ip address!");
        close(sock);
        exit(1);
    }

    char buff[512];
    int len = sizeof(addr);
    while (1)
    {
        gets(buff);
        int n;
	// 直接向服务端发送数据
        n = sendto(sock, buff, strlen(buff), 0, (struct sockaddr *)&addr, sizeof(addr)); 
        if (n < 0)
        {
            perror("sendto");
            close(sock);
            break;
        }
	// 从服务端接受到数据
        n = recvfrom(sock, buff, 512, 0, (struct sockaddr *)&addr, &len);
        if (n>0)
        {
            buff[n] = 0;
            printf("received:");
            puts(buff);
        }
        else if (n==0)
        {
            printf("server closed\n");
            close(sock);
            break;
        }
        else if (n == -1)
        {
            perror("recvfrom");
            close(sock);
            break;
        }
    }
    
    return 0;
}




你可能感兴趣的:(#,网络)