linux下用socket实现一个简单的回射服务器
套接字地址结构sockaddr:
struct sockaddr
{
unsigned short sa_family; /*地址家族, AF_xxx */
char sa_data[14]; /*14字节协议地址*/
};
一般编程并不直接针对此数据结构操作,而是使用另外一个与sockaddr等价的数据结构sockaddr_in(在netinet_in中定义):
struct sockaddr_in
{
short int sin_family; /*通信类型*/
unsigned short int sin_port; /*端口*/
struct in_addr sin_addr; /* Internet地址*/
unsigned char sin_zero[8]; /*与sockaddr结构的长度相同*/
};
主要用到的几个函数
socket()//创建套接字
原型:
原型:int socket(int domain, int type, int protocol) ;
第一个参数domain指定通信协议族(protocol family),第二个为套接字类型(分为流式套接字SOCK_STREAM,数据报套接字SOCK_DGRAM,原始套接字SOCK_RAW),第三个为协议类型
bind()//绑定套接口
原型:
原型:int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
第一个参数sockfd套接字,第二个要绑定的地址,第三个为地址长度
listen()//监听
原型:ssize_t read(int fd, void *buf, size_t count);
第一个参数为已捆绑未连接套接口,第二个参数为最大等待队列的长度,如果未监听到则一直处于等待状态
read()//读函数
原型:ssize_t read(int fd,void *buf,size_t count)
第一个参数fd文件描述符,第二个为指定要读入的缓冲区(指针),第三个为要读入的字节数
该函数的作用是把fd所指的文件传送count个字节读到buf指针所指的内存中
write()//写函数
原型:ssize_t write(int fd, const void *buf, size_t count);
第一个参数fd文件描述符,第二个为指定要写入的缓冲区(指针),第三个为要写入的字节数
还有几个字节转换的函数
将主机地址转换为网络地址
htons() //Host to Network Short"
htonl() //"Host to Network Long"
将网络地址转换为主机地址
ntohs() //"Network to Host Short"
ntohl() //"Network to Host Long"
通信流程:
下面是实现回射服务器的C语言代码:
服务器端:
/*echo server*/
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<unistd.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main()
{
int sockfd;
struct sockaddr_in servaddr; /*服务器端地址*/
struct sockaddr_in peeraddr; /*客户端地址*/
int nfd,ret;
char buffer[1024];
socklen_t peerlen;
memset(&servaddr,0,sizeof(servaddr)); /*初始化*/
servaddr.sin_family = AF_INET; /*指定通信协议族为IPV4*/
servaddr.sin_port = htons(5188); /*绑定端口并转换成网络字符*/
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /*自动填入本机ip地址*/
//servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if((sockfd=socket(AF_INET,SOCK_STREAM,0/*IPPROTO_TCP*/))==-1) /*创建套接字*/
ERR_EXIT("open socket error\n");
else
printf("create socket %d success \n",sockfd);
if(bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) /*将套接字与指定端口地址相绑定*/
ERR_EXIT("bind error\n");
listen(sockfd,SOMAXCONN); /*监听*/
peerlen = sizeof(peeraddr);
if((nfd=accept(sockfd,(struct sockaddr*)&peeraddr,&peerlen)) < 0) /*接受来自客户端的请求*/
ERR_EXIT("accept error\n");
/*nfd is a connected socket byte*/
while(1)
{
memset(buffer,0,sizeof(buffer)); /*清空缓冲区*/
ret = read(nfd,buffer,sizeof(buffer)); /*读取客户端发来的消息*/
fputs(buffer,stdout);
write(nfd,buffer,ret); /*将消息回射给客户端*/
}
close(sockfd); /*关闭套接字*/
close(nfd);
return 0;
}
客户端:
/*echo client*/
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string.h>
#include<unistd.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main()
{
int sock;
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==-1)
ERR_EXIT("ERRO");
struct sockaddr_in servaddr;
char sendbuf[1024] = {0}; /*发送冲区*/
char recvbuf[1024] = {0}; /*接收冲区*/
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(5188);
/*addr.sin_addr = htonl(INADDR_ANY);*/
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) /*将指定的端口地址连接服务器*/
ERR_EXIT("connect error\n");
while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL)
{
write(sock,sendbuf,strlen(sendbuf)); /*发送数据*/
read(sock,recvbuf,sizeof(recvbuf));
fputs(recvbuf,stdout); /*输出从缓冲区读入的服务器端回射回来的信息*/
memset(sendbuf,0,sizeof(sendbuf));
memset(recvbuf,0,sizeof(recvbuf));
}
close(sock);
return 0;
}
测试结果:
客户端:
服务器端: