C++网络编程(socket)我要写一个服务器端程序和一个客户端程序
呵呵,当让可以了。
1、首先我说一下他们的关系:
一个解决方案(sln)中可以包含多个项目(vcxproj);
这些项目可以是互不相关的,也可以是相关的;
2、下面说如何将你的两个项目放在同一个解决方案里
你将一个的项目(B)拷贝到另外一个项目中(A)(其中文件夹A和B中含有vcxproj);
你有Avcxproj和Bvcxproj两个项目,他们分别为
文件夹A(其中含有Avcxproj) 和 文件夹B(其中含有Bvcxproj)
解决方案(Csln)和文件夹A和B在同一目录下。
然后打开对应的解决方案,添加项目,将刚才的B项目添加即可;
3、设置启动项目。
今天太晚了,改天给你做一个,记得提醒我,这个如果只是要个简单的,我半个小时就搞定了
给我个邮箱
现在给贴出我的代码: 整个结构分两个工程
1。服务端工程NioServerjava: 采用nio 方式的异步socket通信,不仅可以实现你的服务器还可以让你多学习一下什么是nio
2。客户端工程UserClientjava: 采用Swing技术画了一个简单的UI界面,比较土,原因是我没那么多时间去设计界面,你需要的话可以自己去修改得漂亮点,相信不难
现在贴工程1:
package comnet;
import javaioIOException;
import javanetInetSocketAddress;
import javanetServerSocket;
import javanioByteBuffer;
import javaniochannelsSelectionKey;
import javaniochannelsSelector;
import javaniochannelsServerSocketChannel;
import javaniochannelsSocketChannel;
import javautilIterator;
import javautilSet;
public class NioServer {
public static final int SERVERPORT=5555;
public static final String USERNAME="wangzhirong";
public static final String PASSWORD="123456";
public static final String ISACK="ACK";
public static final String ISNAK="NAK!";
// Selector selector;//选择器
// SelectionKey key;//key。 一个key代表一个Selector 在NIO通道上的注册,类似主键;
// //取得这个Key后就可以对Selector在通道上进行操作
private ByteBuffer echoBuffer = ByteBufferallocate( 1024 );// 通道数据缓冲区
public NioServer(){
}
public static void main(String[] args) throws IOException {
NioServer ns=new NioServer();
nsBuildNioServer();
}
public void BuildNioServer() throws IOException{
/////////////////////////////////////////////////////////
///////先对服务端的ServerSocket进行注册,注册到Selector ////
/////////////////////////////////////////////////////////
ServerSocketChannel ssc = ServerSocketChannelopen();//新建NIO通道
sscconfigureBlocking( false );//使通道为非阻塞
ServerSocket ss = sscsocket();//创建基于NIO通道的socket连接
//新建socket通道的端口
ssbind(new InetSocketAddress("127001",SERVERPORT));
Selector selector=Selectoropen();//获取一个选择器
//将NIO通道选绑定到择器,当然绑定后分配的主键为skey
SelectionKey skey = sscregister( selector, SelectionKeyOP_ACCEPT );
////////////////////////////////////////////////////////////////////
//// 接收客户端的连接Socket,并将此Socket也接连注册到Selector ////
///////////////////////////////////////////////////////////////////
while(true){
int num = selectorselect();//获取通道内是否有选择器的关心事件
if(num<1){continue; }
Set selectedKeys = selectorselectedKeys();//获取通道内关心事件的集合
Iterator it = selectedKeysiterator();
while (ithasNext()) {//遍历每个事件
try{
SelectionKey key = (SelectionKey)itnext();
//有一个新联接接入事件,服务端事件
if ((keyreadyOps() & SelectionKeyOP_ACCEPT)
== SelectionKeyOP_ACCEPT) {
// 接收这个新连接
ServerSocketChannel serverChanel = (ServerSocketChannel)keychannel();
//从serverSocketChannel中创建出与客户端的连接socketChannel
SocketChannel sc = serverChanelaccept();
scconfigureBlocking( false );
// Add the new connection to the selector
// 把新连接注册到选择器
SelectionKey newKey = scregister( selector,
SelectionKeyOP_READ );
itremove();
Systemoutprintln( "Got connection from "+sc );
}else
//读客户端数据的事件,此时有客户端发数据过来,客户端事件
if((keyreadyOps() & SelectionKeyOP_READ)
== SelectionKeyOP_READ){
// 读取数据
SocketChannel sc = (SocketChannel)keychannel();
int bytesEchoed = 0;
while((bytesEchoed = scread(echoBuffer))> 0){
Systemoutprintln("bytesEchoed:"+bytesEchoed);
}
echoBufferflip();
Systemoutprintln("limet:"+echoBufferlimit());
byte [] content = new byte[echoBufferlimit()];
echoBufferget(content);
String result=new String(content);
doPost(result,sc);
echoBufferclear();
itremove();
}
}catch(Exception e){}
}
}
}
public void doPost(String str,SocketChannel sc){
boolean isok=false;
int index=strindexOf('|');
if(index>0){
String name=strsubstring(0,index);
String pswd=strsubstring(index+1);
if(pswd==null){pswd="";}
if(name!=null){
if(nameequals(USERNAME)
&& pswdequals(PASSWORD)
){
isok=true;
}else{
isok=false;
}
}else{
isok=false;
}
}else{
isok=false;
}
String result="";
if(isok){
result="ACK";
}else{
result="NAK!";
}
ByteBuffer bb = ByteBufferallocate( resultlength() );
bbput(resultgetBytes());
bbflip();
try {
scwrite(bb);
} catch (IOException e) {
eprintStackTrace();
}
bbclear();
}
}
下面贴工程2
import javaawtColor;
import javaawtDimension;
import javaawteventActionEvent;
import javaawteventActionListener;
import javaioIOException;
import javaioInputStream;
import javaioOutputStream;
import javanetSocket;
import javanetUnknownHostException;
import javaxswingJButton;
import javaxswingJFrame;
import javaxswingJLabel;
import javaxswingJPanel;
import javaxswingJPasswordField;
import javaxswingJTextField;
public class UserClient implements ActionListener{
JFrame jf;
JPanel jp;
JLabel label_name;
JLabel label_pswd;
JTextField userName;
JButton jb;
JPasswordField paswrd;
JLabel hintStr;
public UserClient (){
jf=new JFrame("XXX 登陆系统");
jp=new JPanel();
jfsetContentPane(jp);
jfsetPreferredSize(new Dimension(350,220));
jpsetPreferredSize(new Dimension(350,220));
jpsetBackground(Colorgray);
label_name=new JLabel();
label_namesetPreferredSize(new Dimension(150,30));
label_namesetText("请输入帐户(数字或英文):");
userName=new JTextField();
userNamesetPreferredSize(new Dimension(150,30));
jpadd(label_name);
jpadd(userName);
label_pswd=new JLabel();
label_pswdsetPreferredSize(new Dimension(150,30));
label_pswdsetText("请输入密码:");
jpadd(label_pswd);
paswrd=new JPasswordField();
paswrdsetPreferredSize(new Dimension(150,30));
jpadd(paswrd);
jb=new JButton("OK");
jbsetPreferredSize(new Dimension(150,30));
jbsetText("确 定");
jbaddActionListener( this);
jpadd(jb);
hintStr=new JLabel();
hintStrsetPreferredSize(new Dimension(210,40));
hintStrsetText("");
hintStrsetForeground(ColorRED);
jpadd(hintStr);
jfpack();
jfsetVisible(true);
jfsetDefaultCloseOperation(JFrameEXIT_ON_CLOSE);
}
private String name;
private String pswd;
public void actionPerformed(ActionEvent e) {
name=userNamegetText()trim();
pswd=new String(paswrdgetPassword());
if(pswd==null){
pswd="";
}else{
pswd=pswdtrim();
}
if(name!=null && namelength()>0){
hintStrsetText("正在验证客户端,请稍候");
start();
}
}
OutputStream os;
Socket s;
InputStream is;
public void start(){
//建立联网线程
new Thread(new Runnable(){
public void run() {
try {
s=new Socket("127001",5555);
//写
os=sgetOutputStream();
oswrite(namegetBytes());
oswrite('|');//用户名与密码用"|"分隔
oswrite(pswdgetBytes());
osflush();
//读内容
Threadsleep(1000);
is=sgetInputStream();
int len=isavailable();
Systemoutprintln("len:"+len);
byte[] bytes=new byte[len];
isread(bytes);
String resut=new String(bytes);
Systemoutprintln("resut:"+resut);
//TODO 这里通过返回结果处理
if(resutequals("ACK")){
hintStrsetText("验证成功,欢迎光临!");
}else{
paswrdsetText(null);
hintStrsetText("用户名或密码错误,请重新输入");
}
} catch (UnknownHostException e) {
eprintStackTrace();
} catch (IOException e) {
eprintStackTrace();
} catch (InterruptedException e) {
eprintStackTrace();
}finally{
// try {
// osclose();
// isclose();
// sclose();
// } catch (IOException e) {
// eprintStackTrace();
// }
}
}
})start();
}
public static void main(String[] args) {
new UserClient();
}
}
下面是示例程序的简单步骤说明
服务器端:
第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第二步:建立一个Socket对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接受到客户端的连接,用socket对像的Accept()方法创建新的socket对像用于和请求的客户端进行通信;
第六步:通信结束后一定记得关闭socket;
代码:
using System;
using SystemCollectionsGeneric;
using SystemText;
using SystemNet;
using SystemNetSockets;
namespace server
{
class Program
{
static void Main(string[] args)
{
int port = 2000;
string host = "127001";
/////创建终结点(EndPoint)
IPAddress ip = IPAddressParse(host);//把ip地址字符串转换为IPAddress类型的实例
IPEndPoint ipe = new IPEndPoint(ip, port);//用指定的端口和ip初始化IPEndPoint类的新实例
/////创建socket并开始监听
Socket s = new Socket(AddressFamilyInterNetwork, SocketTypeStream, ProtocolTypeTcp);//创建一个socket对像,如果用udp协议,则要用SocketTypeDgram类型的套接字
sBind(ipe);//绑定EndPoint对像(2000端口和ip地址)
sListen(0);//开始监听
ConsoleWriteLine("等待客户端连接");
/////接受到client连接,为此连接建立新的socket,并接受信息
Socket temp = sAccept();//为新建连接创建新的socket
ConsoleWriteLine("建立连接");
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = tempReceive(recvBytes, recvBytesLength, 0);//从客户端接受信息
recvStr += EncodingASCIIGetString(recvBytes, 0, bytes);
/////给client端返回信息
ConsoleWriteLine("server get message:{0}", recvStr);//把客户端传来的信息显示出来
string sendStr = "ok!Client send message successful!";
byte[] bs = EncodingASCIIGetBytes(sendStr);
tempSend(bs, bsLength, 0);//返回信息给客户端
tempClose();
sClose();
ConsoleReadLine();
}
}
}
客户端:
第一步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第二步:建立一个Socket对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket;
代码:
using System;
using SystemCollectionsGeneric;
using SystemText;
using SystemNet;
using SystemNetSockets;
namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
int port = 2000;
string host = "127001";
/////创建终结点EndPoint
IPAddress ip = IPAddressParse(host);
//IPAddress ipp = new IPAddress("127001");
IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndpoint实例
/////创建socket并连接到服务器
Socket c = new Socket(AddressFamilyInterNetwork, SocketTypeStream, ProtocolTypeTcp);//创建Socket
ConsoleWriteLine("Conneting…");
cConnect(ipe);//连接到服务器
/////向服务器发送信息
string sendStr = "hello!This is a socket test";
byte[] bs = EncodingASCIIGetBytes(sendStr);//把字符串编码为字节
ConsoleWriteLine("Send Message");
cSend(bs, bsLength, 0);//发送信息
/////接受从服务器返回的信息
string recvStr = "";
byte[] recvBytes = new byte[1024];
int bytes;
bytes = cReceive(recvBytes, recvBytesLength, 0);//从服务器端接受返回信息
recvStr += EncodingASCIIGetString(recvBytes, 0, bytes);
ConsoleWriteLine("client get message:{0}", recvStr);//显示服务器返回信息
/////一定记着用完socket后要关闭
cClose();
}
catch (ArgumentNullException e)
{
ConsoleWriteLine("argumentNullException: {0}", e);
}
catch (SocketException e)
{
ConsoleWriteLine("SocketException:{0}", e);
}
ConsoleWriteLine("Press Enter to Exit");
}
}
}
先要理解socket是什么?
简单的说socket是一个全双工的通信通道,
即使用TCP或者UDP通信时均可以在发送消息的同时接受消息,
它不区分是否是服务器。
根据这个概念你的问题就很好回答。
》当客户端与服务器连接后。有什么方法使服务器可以随时随地发消息给客户端?
》我现在只能。客户端发个消息给服务器。服务器才能发个消息给客户端。也就是说客户端不发消息。服务器就没法发消息给客户端。
》求大牛给个思路。当连接后。客户端与服务器双方可以随时随地通信!
使用多线程,一个维持接受逻辑,一个维持送信逻辑,即可完成同时接受及发送。
客户端及服务器端均做上述设置。
而你的做法是在一个线程中执行接受与送信,因此只能按照顺序逻辑完成接收与送信。
关键点是多线程。
搭建外网访问,首先你要有一台外网可访问的服务器,有以下几种方法可以实现。
一、购买外网服务器。由于服务器端使用JAVA语言开发,所以外网服务器操作系统可以是Linux或Windows,这个需要你花钱购买。如果只是测试,你可以选择购买阿里云的云服务器,非常便宜。
二、还有一种方法就是你通过花生壳之类的软件进行映射你的网络,但花生壳对长城宽带之类的网络支持不是特别好,如果需要很好的支持,那也需要花钱购买。
三、如果你是通过路由器上网,并且可以操作路由器权限且使用的是电信或者是联通的网络,那可以直接在路由器里面做端口映射,这个你可以百度一下,有很多文章讲的非常清楚,这里篇幅限制,就不贴了。
四、如果你是直接通过猫上网且使用电信或联通宽带,那可以直接使用本机外网IP访问你的程序。
以上四种方法中,最稳定的还是购买外网服务器,其它都会有各种问题,你可以选择其中适合你的一种方法。希望能帮助到你
众所周知TCP(Transmission Control Protocol )是一种面向连接的、可靠的、基于字节流的通信协议。而开发TCP socket应用程序是一件比较简单的事情。下面就用一个比较简单的demo 讲解开发的过程。
该程序分为客户端和服务器端,客户端主要是向服务器端发送数据,服务器端主要是对于接收的数据进行显示。
TCP服务器端和客户端的主要流程:
服务器端:1 创建套接字 2 绑定 3 监听 4 接受连接 5 收发数据 6 关闭
客户端: 1 创建套接字 2 连接 3 收发数据 4 关闭
实现中用到的主要函数及
服务器: 1 WSAStartup() 2 socket() 3 bind() 4 listen() 5 accept() 6 recv() 7 closesocket() 8 WSACleanup()
客户端: 1 WSAStartup() 2 socket() 3 connect() 4 send() 5 closesocket() 6 WSACleanup()
下面是server 和 client 的实现代码,运行的时候首先启动server,然后再启动client, 则在server部分打印出“hello world” 。
0条评论