tcp
http://www.cnblogs.com/xudong-bupt/archive/2013/12/29/3483059.html
http://blog.csdn.net/hguisu/article/details/7445768/
函数层面的3次握手 连接
函数层面的4次挥手
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);
}
.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
改进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命令
udp
http://www.cnblogs.com/uvsjoh/archive/2013/01/01/2841764.html
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
#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;
}
#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;
}