socket实现简单的echo应答服务器和客户端

原创 2015年11月17日 17:02:21
</pre></h6><h6><strong>实现思路</strong></h6><p><span style="white-space:pre"></span>1、使用socket()创建tcp套接字。</p><p><span style="white-space:pre"></span>2、利用bind()给套接字分配端口号。</p><p><span style="white-space:pre"></span>3、使用listen()告诉系统允许对该端口建立连接。</p><p><span style="white-space:pre"></span>4、调用accept()为每个客户连接获取新的套接字。</p><p><span style="white-space:pre"></span>5、使用send()和recv()通过新的套接字与客户端通信。</p><p><span style="white-space:pre"></span>6、使用close()关闭客户连接。</p><p></p><h6>函数和结构体说明:</h6><p><span style="white-space:pre"></span>1、主机字节序和网络字节序的转换</p><p><span style="white-space:pre"><span style="white-space:pre"></span>函数名中,h代表host,就是主机;n代表net 就是网络;l代表long是32位整数;s代表short是16位整数。</span></p><pre name="code" class="cpp">#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
2、socket结构体

IPv4和IPv6的地址格式定义在 netinet.h 中。在IPv4地址中使用sockaddr_in结构体,包括16位的端口号和32位的IP地址。IPv6地址使用sockaddr_in6结构体,包括16位的端口号和128位的ip地址和一些控制字段。

地址结构的第一部分定义了地址族——地址属于的空间。AF_INET和AF_INET6分别代表IPv6和IPv4的Internet地址族。

sockaddr 定义了一种泛型的数据类型,用于指定与套接字关联的地址。

struct sockaddr	{
	sa_family_t sa_family;
	char sa_data[14];
};
struct in_addr {
	uint32_t s_addr;
};

struct sockaddr_in {
	sa_family_t sin_family;
	in_port_t sin_port;
	struct in_addr sin_addr;
	char sin_zero[8];
}
struct in6_addr {
	uint32_t s_addr[16];
};

struct sockaddr_in6 {
	sa_family_t sin6_family;
	in_port_t sin6_port;
	uint32_t sin6_flowinfo;
	struct in6_addr sin6_addr;
	uint32_t sin6_scope_id;
};

sockaddr数据结构


3、二进制/字符串地址转换

// pton = printable to numeric
// addressFamily: 要转换地址的地址族
// src:转换的地址,字符串以null终止
// des:存放结果的地址空间
// 转换成功,返回1;未指定地址族,返回-1;des未格式化成指定类型,返回0。
int inet_pton(int addressFamily, const char *src, void *dst)

// addressFamily:要转换的地址类型。
// src:指向包含要转换的数字地址的内存块
// des:指向在调用这的空间中分配的缓冲区
const char *inet_ntop(int addressFamily, const void *src, char *dst, socklen_t desBytes) 


4、获取套接字关联的地址

// socket:是我们想要获得的地址信息的套接字描述符
// remoteAddress和localAddress :指向把地址信息存放在其中的地址结构
int getpeername(int socket, struct sockaddr *remoteAddress, socklen_t *addressLength)
int getsockname(int socket, struct sockaddr *localAddress, socklen_t *addressLength)

5、创建销毁套接字

// domain:通信领域,IPv4(AF_INET), IPv6(AF_INET6)
// type:SOCK_STREAM表示利用可靠的自截留语义指定一个套接字。SOCK_DGRAM则指定一种"尽力而为"的数据报套接字
// protocal:指定要使用的指定的端到端协议;TCP(IPPROTO_TCP)、UCP(IPPROTO_UCP)
// 返回:-1表示失败;
int socket(int domain, int type, int protocal)
// 释放套接字。
// 返回:0代表成功,-1表示失败
int close(int socket)


6、连接套接字

int connect(int socket, const struct sockaddr *foreignAddress, socklen_t addressLength)

7、绑定到地址

int bind(int socket, struct sockaddr *localAddress, socklen_t addressSize)


8、处理进入连接
int listen(int socket, int queueLimit)
int accept(int socket, struct sockaddr *clientAddress, socklen_t *addressLength)


9、通信

ssize_t send(int socket, const void *msg, size_t msgLength, int flags)
ssize_t recv(int socket, void *rcvBuffer, size_t bufferLength, int flags)




echo服务器代码实现:

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

static const int MAXPENDING = 5;

static const int BUFSIZE = 1024;

void HandleTCPClient(int clntSocket);

void DieWithUserMessage(const char *msg, const char *detail);

void DieWithSystemMessage(const char *msg);

int main(int argc, char *argv[]) {
	if(argc != 2)
		  DieWithUserMessage("Parameter(s)", "<Server Port>");

	in_port_t servPort = atoi(argv[1]);

	// Create socket for incoming connections
	int servSock;
	if((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
		DieWithSystemMessage("Socket() failed");
	}

	// Construct local address structure
	struct sockaddr_in servAddr;			// Local address
	memset(&servAddr, 0, sizeof(servAddr));		// Zero out structure
	servAddr.sin_family =  AF_INET;			// IPv4 address family
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);	// Any incoming interface.
	servAddr.sin_port = htons(servPort);
	
	//Bind to the local address
	if (bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr)) < 0 )
		DieWithSystemMessage("bind() failed");

	// Mark the socket so it will listen for incoming connections
	if (listen(servSock, MAXPENDING) < 0 )
		DieWithSystemMessage("listen() failed");

	for (;;) {					// Run forever
		struct sockaddr_in clntAddr;		// Client address
		// Set length of client address structure (in-out parameter)
		socklen_t clntAddrLen = sizeof(clntAddr);
		
		// Wait for a client to connect
		int clntSock = accept(servSock, (struct sockaddr*) &clntAddr, &clntAddrLen);
		if ( clntSock < 0 )
			DieWithSystemMessage("accept() failed");
		
		// clntSock is connected to a client!
		
		char clntName[INET_ADDRSTRLEN];		// String to contain client address
		if (inet_ntop(AF_INET, &clntAddr.sin_addr.s_addr, clntName, sizeof(clntName)) != NULL )
			printf("Handling client %s/%d\n", clntName, ntohs(clntAddr.sin_port));
		else
			puts("Unable to get client address");

		HandleTCPClient(clntSock);
		
	}
}

void HandleTCPClient(int clntSocket){
	char buffer[BUFSIZE];	// Buffer for echo string
	
	// Receive message from client.
	ssize_t numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
	if ( numBytesRcvd < 0 )
		DieWithSystemMessage("recv() failed");

	// Send received string and receive again until end of stream.
	while ( numBytesRcvd > 0 ) {  //0 indicates end of stream.
		// Echo message back to client.
		ssize_t numBytesSent = send(clntSocket, buffer, numBytesRcvd, 0);
		if ( numBytesSent < 0 )
			DieWithSystemMessage("send() failed");
		else if ( numBytesSent != numBytesRcvd )
			DieWithUserMessage("send()", "send unexpected number of bytes");
		
		// See if there is more data to receive.
		numBytesRcvd = recv(clntSocket, buffer, BUFSIZE, 0);
		if ( numBytesRcvd < 0 )
			DieWithSystemMessage("recv() failed.");
	}
	
	close(clntSocket); 	// Close client socket.
}

void DieWithUserMessage(const char *msg, const char *detail) {
	fputs(msg, stderr);
	fputs(": ", stderr);
	fputs(detail, stderr);
	fputc('\n', stderr);
	exit(1);
}

void DieWithSystemMessage(const char *msg) {
	perror(msg);
	exit(1);
}
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> // IPPROTO_TCP

#include "DieMessage.h"

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

	if ( argc < 3) {
		DieWithUserMessage("Parameter(s)", "<IP><PORT>[<MESSAGE>]");
	}

	// Create local socket
	int sock;
	if ( ( sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) < 0 ) {
		DieWithSystemMessage("socket() failed.");
	} 

	int servPort = atoi(argv[2]);

	// Create server address
	struct sockaddr_in servAddr;
	memset( &servAddr, 0, sizeof(servAddr) );
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(servPort);
	inet_pton(AF_INET, argv[1], &servAddr.sin_addr.s_addr);

	// Connect to server
	if ( (connect( sock, (struct sockaddr *) &servAddr, sizeof(servAddr))) < 0  ) {
		DieWithSystemMessage("connect() failed.");
	}

	// Send Message to server
	ssize_t sentByteLen = send( sock, argv[3], sizeof(argv[3]), 0);
	if ( sentByteLen > 0 ) {
		printf("send: %s\tbytes:%d\n", argv[3], sentByteLen);
	} else {
		DieWithSystemMessage("send() failed");
	}
	
	// Receive Message from server
	char recvBuf[sentByteLen];
	ssize_t recvByteLen = recv( sock, recvBuf, sentByteLen, 0);
	if ( recvByteLen > 0 ) {
		printf("recv: %s\tbytes:%d\n", recvBuf, recvByteLen);
	} else {
		DieWithSystemMessage("recv() failed");
	}

	close(sock);
	
	printf("end!\n");
}


相关文章推荐

linux socke编程实例:一个简单的echo服务器程序

    也许是第一次真正使用linux操作系统,忽然对丢弃已久的C产生了很大的兴趣,最近想学点linux的知识,在linux的世界里面,接触得最多的还是C,故有感写一下linux的socket程序。 ...
  • linyt
  • linyt
  • 2007年07月31日 18:08
  • 7144

linux socke编程实例:一个简单的echo服务器程序(2)

    在文章 <<linux socke编程实例:一个简单的echo服务器程序>>简单地介绍了如何在linix使用socket进行网络编程,并且在文中给出相应的程序和说明,以使大家对socket编程...
  • linyt
  • linyt
  • 2007年08月10日 17:33
  • 3400

linux-echo服务器

写在文章前:         这学习linux编程,也有一段时间了。虽然是一个人看书,琢磨。也想把自己看过的做一个总结,一步一步来,总有一天会质变的。不得不说,linux太博大精深了,里面需要学的东...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

java实现了简单的Echo服务程序分服务器和客户端

Echo回显服务 模拟echo协议
  • JQ_AK47
  • JQ_AK47
  • 2016年06月22日 22:15
  • 1955

java socket通讯之 echo server 和echo client例子

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net...
  • earbao
  • earbao
  • 2013年12月26日 17:50
  • 2914

VC写的socket程序实现一个简单Echo服务器端和客户端程序

VC写的socket程序实现一个简单Echo服务器端和客户端程序,本程序在VS2010中调试通过。...

1.2.3写一个 echo 服务器

写一个 echo 服务器 Netty 实现的 echo 服务器都需要下面这些: 一个服务器 handler:这个组件实现了服务器的业务逻辑,决定了连接创建后和接收到信息后该如何处理Bootst...

[c语言 ] 用libev 写个echo服务器

放假了.同学都回家了,我是更情愿留久点在学校,一来学校安静,二来免得火车太挤.  这临走前的几天,放下了erlang,写了一下c. 其实只是对比下erlang 写socket服务器,和c写socket...
  • dp0304
  • dp0304
  • 2012年07月07日 16:03
  • 11081

TCP实现ECHO程序(服务端同时处理多个客户端的响应)

一、ECHO意为应答,程序的功能是客户端向服务器发送一个字符串,服务器不做任何处理,直接把字符串返回给客户端,ECHO是自己笨的客户/服务器程序。 二、目前为止我们编写的程序中,服务器只能处理一个客...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:socket实现简单的echo应答服务器和客户端
举报原因:
原因补充:

(最多只允许输入30个字)