当前位置: 首页 > wzjs >正文

网站建设的基础天使投资

网站建设的基础,天使投资,WordPress说说心情,北京城建道桥建设网站Socket 编程 TCP TCP 网络程序 和刚才 UDP 类似 . 实现一个简单的英译汉的功能 TCP socket API 详解 下面介绍程序中用到的 socket API, 这些函数都在 sys/socket.h 中。 socket(): • socket() 打开一个网络通讯端口 , 如果成功的话 , 就像 open() 一样返回一个…

Socket 编程 TCP

TCP 网络程序
和刚才 UDP 类似 . 实现一个简单的英译汉的功能
TCP socket API 详解
下面介绍程序中用到的 socket API, 这些函数都在 sys/socket.h 中。
socket():
socket() 打开一个网络通讯端口 , 如果成功的话 , 就像 open() 一样返回一个文件描
述符 ;
应用程序可以像读写文件一样用 read/write 在网络上收发数据 ;
如果 socket() 调用出错则返回 -1;
对于 IPv4, family 参数指定为 AF_INET;
对于 TCP 协议 ,type 参数指定为 SOCK_STREAM, 表示面向流的传输协议
protocol 参数的介绍从略 , 指定为 0 即可。

 bind():

服务器程序所监听的网络地址和端口号通常是固定不变的 , 客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接; 服务器需要调用 bind 绑定一个固定的网络地址和端口号;

bind() 成功返回 0, 失败返回 -1
bind() 的作用是将参数 sockfd myaddr 绑定在一起 , 使 sockfd 这个用于网络
通讯的文件描述符监听 myaddr 所描述的地址和端口号 ;
前面讲过 ,struct sockaddr * 是一个通用指针类型 ,myaddr 参数实际上可以接受
多种协议的 sockaddr 结构体 , 而它们的长度各不相同 , 所以需要第三个参数 addrlen
指定结构体的长度 ;
listen():
listen()申明处于监听状态 , 并且最多允许有 backlog 个客户端处于连接等待状态, 如果接收到更多的连接请求就忽略 , 这里设置不会太大 ( 一般是 5), 具体细节同学们课后深入研究;
listen() 成功返回 0, 失败返回 -1;
accept():
三次握手完成后 , 服务器调用 accept() 接受连接 ;
如果服务器调用 accept() 时还没有客户端的连接请求 , 就阻塞等待直到有客户端
连接上来 ;
addr 是一个传出参数 ,accept() 返回时传出客户端的地址和端口号 ;
如果给 addr 参数传 NULL, 表示不关心客户端的地址 ;
addrlen 参数是一个传入传出参数 (value-result argument), 传入的是调用者提
供的 , 缓冲区 addr 的长度以避免缓冲区溢出问题 , 传出的是客户端地址结构体的实
际长度 ( 有可能没有占满调用者提供的缓冲区 );
理解 accecpt 的返回值 : 饭店拉客例子
connect
客户端需要调用 connect() 连接服务器 ;
connect bind 的参数形式一致 , 区别在于 bind 的参数是自己的地址 ,
connect 的参数是对方的地址 ;
connect() 成功返回 0, 出错返回 -1;
V1 - Echo Server
TcpServer.hpp
C++
#pragma once
#include <iostream>
#include <string>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "nocopy.hpp"
#include "Comm.hpp"
const static int default_backlog = 6; // TODO
class TcpServer : public nocopy
{
public:
TcpServer(uint16_t port) : _port(port), _isrunning(false)
{
}
// 都是固定套路
void Init()
{
// 1. 创建 socket, file fd, 本质是文件
_listensock = socket(AF_INET, SOCK_STREAM, 0);
if (_listensock < 0)
{
lg.LogMessage(Fatal, "create socket error, errno
code: %d, error string: %s\n", errno, strerror(errno));
exit(Fatal);
}
int opt = 1;
setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR |
SO_REUSEPORT, &opt, sizeof(opt));
lg.LogMessage(Debug, "create socket success,
sockfd: %d\n", _listensock);
// 2. 填充本地网络信息并 bind
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(_port);
local.sin_addr.s_addr = htonl(INADDR_ANY);
// 2.1 bind
if (bind(_listensock, CONV(&local), sizeof(local)) != 0)
{
lg.LogMessage(Fatal, "bind socket error, errno
code: %d, error string: %s\n", errno, strerror(errno));
exit(Bind_Err);
}
lg.LogMessage(Debug, "bind socket success, sockfd: %d\n",
_listensock);
// 3. 设置 socket 为监听状态,tcp 特有的
if (listen(_listensock, default_backlog) != 0)
{
lg.LogMessage(Fatal, "listen socket error, errno
code: %d, error string: %s\n", errno, strerror(errno));
exit(Listen_Err);
}
lg.LogMessage(Debug, "listen socket success,
sockfd: %d\n", _listensock);
}
// Tcp 连接全双工通信的.
void Service(int sockfd)
{
char buffer[1024];
// 一直进行 IO
while (true)
{
ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
if (n > 0)
{
buffer[n] = 0;
std::cout << "client say# " << buffer <<
std::endl;
std::string echo_string = "server echo# ";
echo_string += buffer;
write(sockfd, echo_string.c_str(),
echo_string.size());
}
else if (n == 0) // read 如果返回值是 0,表示读到了文件结
尾(对端关闭了连接!)
{
lg.LogMessage(Info, "client quit...\n");
break;
}
else
{
lg.LogMessage(Error, "read socket error, errno
code: %d, error string: %s\n", errno, strerror(errno));
break;
}
}
}
void Start()
{
_isrunning = true;
while (_isrunning)
{
// 4. 获取连接
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
int sockfd = accept(_listensock, CONV(&peer), &len);
if (sockfd < 0)
{
lg.LogMessage(Warning, "accept socket error, errno
code: %d, error string: %s\n", errno, strerror(errno));
continue;
}
lg.LogMessage(Debug, "accept success, get n new
sockfd: %d\n", sockfd);
// 5. 提供服务啊, v1~v4
// v1
Service(sockfd);
close(sockfd);
}
}
~TcpServer()
{
}
private:
uint16_t _port;
int _listensock; // TODO
bool _isrunning;
};
Comm.hpp
C++
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
enum{
Usage_Err = 1,
Socket_Err,
Bind_Err,
Listen_Err
};
#define CONV(addr_ptr) ((struct sockaddr *)addr_ptr)

TcpClient.cc

C++
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Comm.hpp"
using namespace std;
void Usage(const std::string &process)
{
std::cout << "Usage: " << process << " server_ip server_port"
<< std::endl;
}
// ./tcp_client serverip serverport
int main(int argc, char *argv[])
{
if (argc != 3)
{
Usage(argv[0]);
return 1;
}
std::string serverip = argv[1];
uint16_t serverport = stoi(argv[2]);
// 1. 创建 socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
cerr << "socket error" << endl;
return 1;
}
// 2. 要不要 bind?必须要有 Ip 和 Port, 需要 bind,但是不需要用户显
示的 bind,client 系统随机端口
// 发起连接的时候,client 会被 OS 自动进行本地绑定
// 2. connect
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(serverport);
// p:process(进程), n(网络) -- 不太准确,但是好记忆
inet_pton(AF_INET, serverip.c_str(), &server.sin_addr); // 1. 字符串 ip->4 字节 IP 2. 网络序列
int n = connect(sockfd, CONV(&server), sizeof(server)); // 自动进行 bind 哦!
if(n < 0)
{
cerr << "connect error" << endl;
return 2;
}
// 并没有向 server 一样,产生新的 sockfd.未来我们就用 connect 成功的
sockfd 进行通信即可.
while(true)
{
string inbuffer;
cout << "Please Enter# ";
getline(cin, inbuffer);
ssize_t n = write(sockfd, inbuffer.c_str(),
inbuffer.size());
if(n > 0)
{
char buffer[1024];
ssize_t m = read(sockfd, buffer, sizeof(buffer)-1);
if(m > 0)
{
buffer[m] = 0;
cout << "get a echo messsge -> " << buffer <<
endl;
}
else if(m == 0 || m < 0)
{
break;
}
}
else
{
break;
}
}
close(sockfd);
return 0;
}
由于客户端不需要固定的端口号 , 因此不必调用 bind() , 客户端的端口号由内核自动分配
注意 :
客户端不是不允许调用 bind(), 只是没有必要显示的调用 bind() 固定一个端口号. 否则如果在同一台机器上启动多个客户端 , 就会出现端口号被占用导致不能正确
建立连接 ;
服务器也不是必须调用 bind(), 但如果服务器不调用 bind(), 内核会自动给服务器分配监听端口, 每次启动服务器时端口号都不一样 , 客户端要连接服务器就会遇到
麻烦 ;
测试多个连接的情况
再启动一个客户端 , 尝试连接服务器 , 发现第二个客户端 , 不能正确的和服务器进行通信 . 分析原因, 是因为我们 accecpt 了一个请求之后 , 就在一直 while 循环尝试 read , 没有继续调用到 accecpt , 导致不能接受新的请求 .
我们当前的这个 TCP , 只能处理一个连接 , 这是不科学的。

文章转载自:

http://ueo1YxCH.skksz.cn
http://9demQXOL.skksz.cn
http://VwlP9fcT.skksz.cn
http://gNLZTI7X.skksz.cn
http://R2GS92ed.skksz.cn
http://Xlr37NGM.skksz.cn
http://9ZcmQ1Wn.skksz.cn
http://v3dNGH3E.skksz.cn
http://q8QsAEgg.skksz.cn
http://8Mu6HQy2.skksz.cn
http://D9bQbhvr.skksz.cn
http://6UxqNsRa.skksz.cn
http://TbLzgrra.skksz.cn
http://JDaDwDgV.skksz.cn
http://yUsfdZQO.skksz.cn
http://cVdKtE1Q.skksz.cn
http://kXW7CaXt.skksz.cn
http://2qk8pTct.skksz.cn
http://Q6juuLWC.skksz.cn
http://lhn5DHmR.skksz.cn
http://iaJ1vd0r.skksz.cn
http://AACtGq6J.skksz.cn
http://RS9ORkxH.skksz.cn
http://ici0qt61.skksz.cn
http://Wvoo5zua.skksz.cn
http://8xiONVih.skksz.cn
http://6GIWBqGs.skksz.cn
http://84e2LwSB.skksz.cn
http://cEN7SplS.skksz.cn
http://TrSIzkvK.skksz.cn
http://www.dtcms.com/wzjs/739087.html

相关文章:

  • 西安个人做企业网站南京专业做网站的公司有哪些
  • 徐州建设工程审图中心网站响应式网站和普通网站
  • 西安网站设计试听四川建设机械网站首页
  • 沧州做企业网站公司建网站怎样才能通过备案
  • 北京旅游网站建设网站做的好的医院
  • 濮阳网站建设兼职百度收录有什么用
  • 小白如何搭建一个网站同学录网站开发的背景
  • 四川网站开发农产品销售平台
  • 设计之窗网站phpmysql网站开发技术项目式教程
  • 个人网站怎么做微商怎样与知名网站做友情链接
  • 怎么做wp网站jsp网站建设技术案例
  • 太原定制网站制作流程wordpress 仿百度模板
  • 专业做网站建设公司好吗做网站步骤
  • 做视频直播类型的网站设计资料网站
  • 网站建设 石景山黔东南网站开发
  • 一般网站的流量是多少商城网站建
  • 什么是多页面网站wordpress开发周期
  • c2c模式介绍wordpress手机优化
  • 深圳网站设计很棒 乐云践新什么是网络营销产生的现实基础
  • 建公司网站设计网站公司平面设计学徒工资一般多少
  • 长春建设厅官方网站怎么建一个公司运营网站
  • 北京社招网站wordpress调用一篇
  • phpcms 怎么做视频网站首页wordpress是哪种服务器
  • 微网站怎么制作软件编程学什么专业
  • 合肥哪家公司做网站网站运营做网页设计
  • 有风险的网站苏州绿叶网站建设
  • 想做网站平面图设计软件有哪些
  • 网站关键词是什么网站备案信息被注销
  • 长沙网站推广公司广东省工程建设注册中心网站
  • 做海报有哪些网站大连市建设工程电子文件编辑软件