linux网络编程之简单的回射服务器

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;
}


测试结果:

客户端:


服务器端:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值