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; }
#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(); } } }
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(); } }
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对象,利用回调函数循环监听接收发送数据,是更高层次的封装。