今天抽空看了一些简单的东西,主要是对服务器server和客户端client的简单实现。

面向连接的server和client,其工作流程如下图所示:

服务器和客户端将按照这个流程就行开发。。(个人觉得:通过这个流程图,Server应该要先于Client启动,不然Client的connect函数的执行就会出错啦,不知道我的个人感觉对不对,后面试试就知道了。。O(∩_∩)O~)

注意:上图的Server和Client的工作流程是基于面向有连接通信的工作流程,如果是无连接的通信,则不必调用listen和accept。 在无连接的通信中,Server调用recvfrom函数来接收消息

在编写服务器和客户端之前,需要对TCP状态有所了解。。在server和client通信之间,二者都是通过发送/接收不同的信号来改变自己的状态,其tcp状态转换图如下:

了解了二者的开发流程,就可以通过接口来具体实现。

简单的server代码实现:

 #include"winsock2.h"
#include<iostream>
using namespace std;
//This line is very important #pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET ListeningSocket;
SOCKET NewConnection;
SOCKADDR_IN ServerAddr;
SOCKADDR_IN ClientAddr;
int ClientAddrLen;
int Port = ;
int Ret;
char DataBuffer[]; if ((Ret = WSAStartup(MAKEWORD(,), &wsaData)) != )
{
cout<<"WSAStartup failed with error "<<Ret<<endl;
//here no WSACleanup,because we do not create anything;
return -;
} // Create a new socket to listening for client connections.
ListeningSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( INVALID_SOCKET == ListeningSocket)
{
cout<<"Socket failed with error "<<WSAGetLastError()<<endl;
WSACleanup();
return -;
} ServerAddr.sin_family = AF_INET;
ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
ServerAddr.sin_port = htons(Port); //to bind
if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
{
cout<<"Binding failed with error "<<WSAGetLastError()<<endl;
closesocket(ListeningSocket);
WSACleanup();
return -;
} // Listen for client connections. We used a backlog of 5 which is
// normal for many applications. if (listen(ListeningSocket,) == SOCKET_ERROR)
{
cout<<"Listen failed with error "<<WSAGetLastError()<<endl;
closesocket(ListeningSocket);
WSACleanup();
return -;
} cout<<"** We are waiting for a connection on port "<<Port<<"**"<<endl; //accep a connection when one arrives NewConnection = accept(ListeningSocket,(SOCKADDR*)&ClientAddr,&ClientAddrLen);
if (INVALID_SOCKET == NewConnection)
{
cout<<"Accept failed with error "<<WSAGetLastError()<<endl;
closesocket(ListeningSocket);
WSACleanup();
return -;
} cout<<"** We successfully got a connection from "<<inet_ntoa(ClientAddr.sin_addr)
<<":port "<<ntohs(ClientAddr.sin_port)<<"!!**"<<endl; closesocket(ListeningSocket);
cout<<"** We are waiting for data...**\n"; Ret = recv(NewConnection,DataBuffer,sizeof(DataBuffer),);
if (SOCKET_ERROR == Ret)
{
cout<<"Recv failed with error "<<WSAGetLastError()<<endl;
closesocket(NewConnection);
WSACleanup();
return -;
} cout<<"**We have successfully recieve "<<Ret<<" Byte(s) data!**\n"; cout<<"**We are going to close the client connection...**\n"; closesocket(NewConnection);
WSACleanup(); return ;
}

Server Code

客户端的实现:

 #include"winsock2.h"
#include<iostream>
using namespace std;
//This line is very important #pragma comment(lib,"ws2_32.lib")
int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET s;
SOCKADDR_IN ServerAddr;
int Port = ;
int Ret; if (argc <= )
{
cout<<"USAGE: tcpclient <Server IP address>.\n";
return -;
} // Initialize Winsock version 2.2 if ((Ret = WSAStartup(MAKEWORD(,), &wsaData)) != )
{
cout<<"WSAStartup failed with error "<<Ret<<endl;
return -;
} // Create a new socket to make a client connection. s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == s)
{
cout << "socket failed with error " << WSAGetLastError()<<endl;
WSACleanup();
return -;
} ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
ServerAddr.sin_addr.s_addr = inet_addr(argv[]); // Make a connection to the server with socket s. cout<< "We are trying to connect to " << inet_ntoa(ServerAddr.sin_addr)
<< ":" << htons(ServerAddr.sin_port) << "...\n"; if (connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr))
== SOCKET_ERROR)
{
cout << "connect failed with error " << WSAGetLastError() << endl;
closesocket(s);
WSACleanup();
return -;
} cout << "Our connection succeeded.\n"; cout << "We will now try to send a hello message.\n"; if ((Ret = send(s, "Hello", , )) == SOCKET_ERROR)
{
cout << "send failed with error " << WSAGetLastError()<<endl;
closesocket(s);
WSACleanup();
return -;
} cout << "We successfully sent " << Ret << " byte(s).\n"; // When you are finished sending and receiving data on socket s,
// you should close the socket. cout << "We are closing the connection.\n"; closesocket(s); // When your application is finished handling the connection, call
// WSACleanup. WSACleanup();
return ;
}

Client Code

咦,奇了怪了,按照书上的代码,执行起来居然报错。。这是咋回事啊。。

运行Server时,出现这样的错误:

通过报错信息可以知道是accept函数出错了。

那就对症下药,哪儿错儿改哪儿。。

上网查找资料,找到accept函数定义:

SOCKET accept(
__in SOCKET s,
__out struct sockaddr *addr,
__inout int *addrlen
);

第一个参数就是套接字描述符,第二个参数是,接受客户端基本信息的结构体,第三参数很重要,是准备接受结构体的大小,上面的程序 int ClientAddrLen;传进去的时候只是把未知的ClientAddrLen的地址传进去,要传进去的应该是接收这些信息的基本大小啊,所以 得加ClientAddrLen = sizeof(SOCKADDR);。这样程序就执行accept。

注意:客户端需要在服务器运行的时候才能执行,不然会出错的。。

运行Server和Client(需要ip作为main函数的参数,不会的自己百度怎样在VS2008中给main传递参数),二者可以连接了。。执行还没有实现二者的通信。。。呜呜~~~~(>_<)~~~~

拓展:

观察Server中的recv函数和Client中send函数,我想是否可以利用无限循环的方式在Client端输入字符串,在Server端打印该字符串?----就像聊天一样,你输入一句,我这边就显示这一句。。。只是这样只能是单工方式的传输,不能从Server发送到Client端。。那是否可以考虑多线程呢,一个线程运行Server,一个线程运行Client。。??

Winsock网络编程笔记(2)----基于TCP的server和client的更多相关文章

  1. Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计

    http://blog.sina.com.cn/s/blog_48d4cf2d0101859x.html 谈谈网络编程中应用层(基于TCP/UDP)的协议设计 (2013-04-27 19:11:00 ...

  2. Winsock网络编程笔记(3)----基于UDP的server和client

    在上一篇随笔中,对Winsock中基于tcp面向连接的Server和Client通信进行了说明,但是,Winsock中,Server和Client间还可以通过无连接通信,也就是采用UDP协议.. 因此 ...

  3. Winsock网络编程笔记(1)----入门

    今天第一次接触winsock网络编程,看的资料是Windows网络编程第二版.通过博客记住自己的看书笔记.. 在这里贴出第一个程序,虽然程序什么都没做,但以此作为入门,熟悉其网络编程风格.. #inc ...

  4. Linux 系统编程 学习:008-基于socket的网络编程3:基于 TCP 的通信

    背景 上一讲我们介绍了 基于UDP 的通信 这一讲我们来看 TCP 通信. 知识 TCP(Transmission Control Protoco 传输控制协议). TCP是一种面向广域网的通信协议, ...

  5. 网络编程应用:基于TCP协议【实现对象传输】--练习

    要求: 基于TCP协议实现,客服端向服务器发送一个对象 服务器接受并显示用户信息 ,同时返回给客户端 "数据已收到" 建一个Student类,属性:name age Student ...

  6. 网络编程应用:基于TCP协议【实现文件上传】--练习

    要求: 基于TCP协议实现一个向服务器端上传文件的功能 客户端代码: package Homework2; import java.io.File; import java.io.FileInputS ...

  7. 网络编程应用:基于TCP协议【实现一个聊天程序】

    要求: 基于TCP协议实现一个聊天程序,客户端发送一条数据,服务器端发送一条数据 客户端代码: package Homework1; import java.io.IOException; impor ...

  8. Winsock网络编程笔记(4)----基本的理论知识

    前面的笔记记录了Winsock的入门编程,领略了Winsock编程的乐趣..但这并不能算是掌握了Winsock,加深理论知识的理解才会让后续学习更加得心应手..因此,这篇笔记将记录一些有关Winsoc ...

  9. Java基础知识强化之网络编程笔记13:TCP之TCP协议上传图片并给出反馈

    1. TCP协议上传图片并给出反馈: (1)客户端: package cn.itcast_13; import java.io.BufferedInputStream; import java.io. ...

随机推荐

  1. LCA问题第二弹

    LCA问题第二弹 上次用二分的方法给大家分享了对 LCA 问题的处理,各位应该还能回忆起来上次的方法是由子节点向根节点(自下而上)的处理,平时我们遇到的很多问题都是正向思维处理困难而逆向思维处理比较容 ...

  2. Codevs1380没有上司的舞会_KEY

    没有上司的舞会 1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目描述 Description Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系 ...

  3. Ubuntu16.04下安装mysql

    系统信息 (lsb_release -a) Distributor ID: Ubuntu Description: Ubuntu 16.04.2 LTS Release: 16.04 Codename ...

  4. web应用中的异常处理

    楼主前几天写了一篇“Java子线程中的异常处理(通用)”文章,介绍了在多线程环境下3种通用的异常处理方法. 但是平时大家的工作一般是基于开发框架进行的(比如Spring MVC,或Spring Boo ...

  5. JavaScript设计模式接口

    JavaScript中实现接口的方法有三种: 第一种,使用注释的方法实现接口 特点:(1)最简单,但是功能最弱(2)利用 interface和 implement"文字"(3)把他 ...

  6. DAO与DTO

    DAO叫数据访问对象(data access object) DTO是数据传输对象(data transfer object) DAO通常是将非对象数据(如关系数据库中的数据)以对象的方式操纵.(即一 ...

  7. Linux常见命令集锦

    这是平常用到的命令在这里做一下总结: 一.python 类1.pip(已安装)pip用来安装来自PyPI(https://www.python.org/)的python所有的依赖包,并且可以选择安装任 ...

  8. ASP.NET没有魔法——ASP.NET与数据库

    在之前的文章中介绍了使用ASP.NET MVC来开发一个博客系统,并且已将初具雏形,可以查看文章列表页面,也可以点击文章列表的其中一篇文章查看详情,这已经完成了最开始需求分析的读者的查看列表和查看文章 ...

  9. 纠错:基于FPGA串口发送彩色图片数据至VGA显示

    今天这篇文章是要修改之前的一个错误,前面我写过一篇基于FPGA的串口发送图片数据至VGA显示的文章,最后是显示成功了,但是显示的效果图,看起来确实灰度图,当时我默认我使用的MATLAB代码将图片数据转 ...

  10. MVC中重写RoleProvider角色管理

    /* 数据表SQL脚本 if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_UsersInRoles_Ro ...