echo网络服务做为初步网络编程的基础。
下面的echo服务,部分是以前写的,部分今天写的,做复习及以后备查之用。
监听本地的8880端口。均以telnet为客户端做的测试(telnet 127.0.0.1 8880)。
检查到换行时,就把一行数据返回给客户端。
C版:
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
//初始化
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0){
printf("init error");
return 0;
}
//创建socket
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET){
printf("socket error");
WSACleanup();
return 0;
}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8880);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
//绑定IP和端口
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){
printf("bind error");
WSACleanup();
return 0;
}
//监听端口
if (listen(slisten,5)==SOCKET_ERROR)
{
printf("listen error!");
WSACleanup();
return 0;
}
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[128];
printf("wait for client connection...\r\n");
//等待连接
sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET){
printf("accept error!");
WSACleanup();
return 0;
}
printf("accept client: %s:%d\r\n", inet_ntoa(remoteAddr.sin_addr),ntohs(remoteAddr.sin_port));
int offsetLen = 0;
int ret = 0;
//接收数据
while (true){
ret = recv(sClient, revData+offsetLen, 128-offsetLen, 0);
if (ret > 0){
offsetLen += ret;
if (offsetLen >= 128 || revData[offsetLen - 1] == 0x0a){
revData[offsetLen - 1] = 0x00;
break;
}
}
else{
break;
}
}
printf("recive message: %s", revData);
//发送数据
send(sClient, revData, strlen(revData), 0);
//释放资源
closesocket(sClient);
closesocket(slisten);
WSACleanup();
return 0;
}
C++版(利用的boost的asio库,编译需要添加boost到路径中去):
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
class EchoConection
:public boost::enable_shared_from_this<EchoConection>
{
public:
typedef boost::shared_ptr<EchoConection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new EchoConection(io_service));
}
tcp::socket & socket()
{
return socket_;
}
void start()
{
std::cout<<socket_.remote_endpoint().address()<<":";
std::cout<<socket_.remote_endpoint().port()<<" conction\n";
boost::system::error_code error;
handle_read(error,0);
}
private:
EchoConection(boost::asio::io_service& io_service)
:socket_(io_service)
{
}
void handle_write(const boost::system::error_code &error ,size_t transftran)
{
if (!error)
{
if (buf_[0]=='\n')
{
std::cout<<"recive message: "<<ss_.str()<<std::endl;
ss_<<"\n";
boost::asio::async_write(socket_,boost::asio::buffer(ss_.str()),
boost::bind(&EchoConection::handle_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
ss_.str("");
}
else if(buf_[0]== 'q')
{
std::cout<<socket_.remote_endpoint().address()<<":";
std::cout<<socket_.remote_endpoint().port()<<" realse conction\n";
socket_.close();
}
else
{
ss_<<buf_[0];
boost::system::error_code error;
handle_read(error,0);
}
}
else
{
std::cout<<error.message()<<std::endl;
}
}
void handle_read(const boost::system::error_code & error ,size_t transftran)
{
if (!error)
{
boost::asio::async_read(socket_,boost::asio::buffer(buf_),
boost::asio::transfer_at_least(1),
boost::bind(&EchoConection::handle_write,
shared_from_this(),
boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout<<error.message()<<std::endl;
}
}
tcp::socket socket_;
std::stringstream ss_;
char buf_[1];
};
class EchoService
{
public:
EchoService(boost::asio::io_service& io_service)
:acceptor_(io_service,tcp::endpoint(tcp::v4(),8880))
{
start_accept();
}
private:
void start_accept()
{
EchoConection::pointer new_connection =
EchoConection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&EchoService::handle_accept,this,new_connection,
boost::asio::placeholders::error));
}
void handle_accept(EchoConection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
}
start_accept();
}
tcp::acceptor acceptor_;
};
int RunEchoService_main()
{
try
{
boost::asio::io_service io_service;
EchoService server(io_service);
io_service.run();
}
catch(std::exception & e)
{
std::cerr<<e.what()<<std::endl;
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
RunEchoService_main();
return 0;
}
C#版:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace EchoService
{
class Program
{
static void Main(string[] args)
{
int port = 8880;
string host = "127.0.0.1";
IPAddress ip = IPAddress.Parse(host);
IPEndPoint ipe = new IPEndPoint(ip, port);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Bind(ipe);
s.Listen(0);
Console.WriteLine("wait for client connection...");
Socket csocket = s.Accept();
Console.WriteLine("accept client: "+csocket.RemoteEndPoint.ToString());
string recvStr = "";
byte[] recvBytes = new byte[128];
int offsetLen = 0;
while(true){
csocket.Receive(recvBytes, offsetLen, 1,SocketFlags.None);
offsetLen++;
if (offsetLen >= 128 || (recvBytes[offsetLen - 1] == 0x0d))
{
break;
}
}
recvStr += Encoding.ASCII.GetString(recvBytes, 0, offsetLen-1);
Console.WriteLine("recive message: {0}", recvStr);
csocket.Send(Encoding.ASCII.GetBytes(recvStr));
csocket.Close();
Console.ReadLine();
}
}
}
java版:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SimpleEchoService {
public static void main(String[] args) throws IOException {
String host = "127.0.0.1";
int port = 8880;
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress(host,port));
System.out.println("wait for client connection...");
Socket cs = ss.accept();
System.out.println("accept client: "+cs.getRemoteSocketAddress());
OutputStream os = cs.getOutputStream();
InputStream is = cs.getInputStream();
byte [] bys = new byte[128];
int offsetLen=0;
while(true){
is.read(bys, offsetLen, 1);
offsetLen++;
if(offsetLen >= 128 || bys[offsetLen-1]==0x0d){
break;
}
}
System.out.println("revice message: "+new String(bys));
os.write(bys);
is.close();
os.close();
cs.close();
ss.close();
}
}
python版:
import socket
import sys
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_address = ('localhost',8880);
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)
sock.listen(1)
while True:
print >> sys.stderr, 'waiting for a connection'
connection,client_address = sock.accept()
try:
print >>sys.stderr,'connectino from',client_address
line="";
while True:
data = connection.recv(16)
if data=="\r\n":
break;
line=line+data;
print >>sys.stderr,"received message: %s " % line
if line:
print >>sys.stderr,"sending data back to the client"
connection.sendall(line)
else:
print >> sys.stderr,"no data from",client_address
break;
finally:
connection.close()
总结:
1,python,java,C#版代码都比较简单易懂。大概流程就是构造socket,绑定,监听,接收数据,发送数据,关闭资源
2,C写的比较长,但是它们基础,因为window系统中,java,C#,python,基本上都是调用的WSA系列函数接口。
3,C++写的比较复杂,因用用的asio库, 就是一个connection对象,一个service对象,利用回调函数循环监听接收发送数据,是更高层次的封装。