C++服务器(一):了解Linux下socket编程
来源:互联网 发布:无锡汽车模具编程招聘 编辑:程序博客网 时间:2024/05/21 02:34
最近想要用C++写个socket的服务器,用于日常的项目开发。
不过,我是新手,那就慢慢地学习一下吧。
首先,先写一段程序,用起来先。
感谢博文: Linux下 C++调用C 实现socket网络通讯编程 - 雕戈 - ITeye技术网站
Server
#include<iostream>using namespace std;//head files of Linux#include<netinet/in.h>#include<unistd.h> //for fork and read#include<sys/types.h> //for socket#include<sys/socket.h> //for socket#include<string.h> // for bzero#include<arpa/inet.h>void server(){ const unsigned short SERVERPORT = 53556; const int BACKLOG = 10; //10 个最大的连接数 const int MAXSIZE = 1024; int sock, client_fd; sockaddr_in myAddr; sockaddr_in remoteAddr; sock = socket(AF_INET, SOCK_STREAM, 0); //create socket if( sock == -1) { cerr<<"socket create fail!"<<endl; exit(1); } cout<<"sock :"<<sock<<endl; //bind myAddr.sin_family = AF_INET; myAddr.sin_port = htons(SERVERPORT); myAddr.sin_addr.s_addr = INADDR_ANY; bzero( &(myAddr.sin_zero), 8); if(bind(sock, (sockaddr*)(&myAddr), sizeof(sockaddr)) ==-1 ) { cerr<<"bind error!"<<endl; exit(1); } //listen if(listen(sock, BACKLOG) == -1) { cerr<<"listen error"<<endl; exit(1); } while(true) { unsigned int sin_size = sizeof(sockaddr_in); if( (client_fd = accept(sock, (sockaddr*)(&remoteAddr), &sin_size)) ==-1 ) { cerr<<"accept error!"<<endl; continue; } cout<<"Received a connection from "<<static_cast<char*>(inet_ntoa(remoteAddr.sin_addr) )<<endl; //子线程 if(!fork() ) { int rval; char buf[MAXSIZE]; if( (rval = read(client_fd, buf, MAXSIZE) ) <0) { cout<<"Reading stream error!\n"; continue; } cout<<buf<<endl; //向客户端发送信息 const char* msg = "Hello, I am xiaojian. You are connected !"; if( send(client_fd, const_cast<char*>(msg), strlen(msg), 0) == -1) cerr<<"send error!"<<endl; close(client_fd); exit(0); } }} int main(){ server();}
Client
#include<iostream>using namespace std;#include<string.h>#include<netinet/in.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<unistd.h>void client(){ const unsigned short SERVERPORT = 53556; const int MAXSIZE = 1024; const char* SERVER_IP = "115.159.90.99"; const char* DATA = "this is a client message "; int sock, recvBytes; char buf[MAXSIZE];// hostent *host; sockaddr_in serv_addr; if( (sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { cerr<<"socket create fail!"<<endl; exit(1); } bzero( &serv_addr, sizeof(serv_addr) ); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERVERPORT); serv_addr.sin_addr.s_addr = inet_addr(SERVER_IP); if( connect(sock, (sockaddr*)&serv_addr, sizeof(sockaddr)) == -1) { cerr<<"connect error"<<endl; exit(1); } write(sock, const_cast<char*>(DATA), strlen(DATA) ); if( (recvBytes = recv(sock, buf, MAXSIZE, 0)) == -1) { cerr<<"recv error!"<<endl; exit(1); } buf[recvBytes] = '\0'; cout<<buf<<endl; close(sock);}int main(){ client();}
代码比较容易理解,主要是各种 API 的理解和使用。
一些函数和结构
sockaddr_in
解释一下代码:
首先看到一个结构体:sockaddr_in
,这是什么结构呢 sockaddr_in
在头文件in.h
中声明,这个头文件在/usr/include/netinet/
目录下,去一看究竟,可以找到它的声明:
/* Structure describing an Internet socket address. */struct sockaddr_in { __SOCKADDR_COMMON (sin_); in_port_t sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; };
一个比较好的解释:sockaddr和sockaddr_in的区别 - The time is passing - ITeye技术网站
(其实我并不懂,所以暂时不解释)
但是这里要提到的几句代码:
myAddr.sin_family = AF_INET; myAddr.sin_port = htons(SERVERPORT); myAddr.sin_addr.s_addr = INADDR_ANY; bzero( &(myAddr.sin_zero), 8);
其中 AF_INET 定义了协议族(TCP\UDP等)。
socket函数
函数名: socket(建立一个socket通信)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int socket(int domain,int type,int protocol);
函数说明: socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一通信端口。参数domain 指定使用何种的地址类型,完整的定义在/usr/include/bits/socket.h内。
返回值: 成功则返回socket处理代码,失败返回-1。
bind函数
函数名: bind(对socket定位)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
函数说明: bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain定义了一个通用的数据结构
返回值: 成功则返回0,失败返回-1,错误原因存于errno中。
listen函数
函数名: listen(等待连接)
表头文件:#include<sys/socket.h>
定义函数:int listen(int s,int backlog);
函数说明: listen()用来等待参数s 的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端将收到ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client端连线的是accept()。通常listen()会在socket(),bind()之后调用,接着才调用accept()。
返回值: 成功则返回0,失败返回-1,错误原因存于errno。
附加说明: listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET则参数backlog 最大值可设至128。
accept函数
函数名: accept(接受socket连线)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int accept(int s,struct sockaddr * addr,int * addrlen);
函数说明: accept()用来接受参数s的socket连线。参数s的socket必需先经bind()、listen()函数处理过,当有连线进来时accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的地址数据,参数addrlen为scokaddr的结构长度。关于结构sockaddr的定义请参考bind()。
返回值: 成功则返回新的socket处理代码,失败返回-1,错误原因存于errno中。
send函数
函数名: send(经socket传送数据)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int send(int s,const void * msg,int len,unsigned int falgs);
函数说明: send()用来将数据由指定的socket 传给对方主机。参数s为已建立好连接的socket。参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般设0。
返回值: 成功则返回实际传送出去的字符数,失败返回-1。错误原因存于errno
recv函数
函数名: recv(经socket接收数据)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int recv(int s,void *buf,int len,unsigned int flags);
函数说明: recv()用来接收远端主机经指定的socket传来的数据,并把数据存到由参数buf 指向的内存空间,参数len为可接收数据的最大长度。
返回值: 接收的实际长度
connect函数
函数名: connect(建立socket连线)
表头文件:#include<sys/types.h>
#include<sys/socket.h>
定义函数:int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
函数说明: connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
返回值: 成功则返回0,失败返回-1,错误原因存于errno中。
其他函数
read : 由已打开的文件读取数据
write: 将数据写入已打开的文件内
htons:将16位主机字符顺序转换成网络字符顺序
bzero:将一段内存内容全清为零
inet_addr:将网络地址转成二进制的数字
函数可以在参考资料中的Linux 常用手册找到。
但为了代码的可兼容性,我个人的意见是,尽量少用依赖于平台的函数,多用标准库,这样代码可以轻易移植到其他支持 C++ 编译的平台。
参考资料:
Linux下 C++调用C 实现socket网络通讯编程 - 雕戈 - ITeye技术网站
sockaddr和sockaddr_in的区别 - The time is passing - ITeye技术网站
简单理解Socket - Samaritans - 博客园
Linux 常用C函数(中文版)
- C++服务器(一):了解Linux下socket编程
- Linux下Socket编程学习(一)
- linux下网络socket编程(一)
- linux下 socket编程(基于c)
- Linux下Socket编程(一)
- linux下SOCKET编程一
- linux下socket c 编程
- Linux下Socket编程一 socket 基础
- linux下socket编程之时间服务器
- Linux下的socket编程-服务器
- Linux下Socket服务器与客户端编程
- Linux下C编程 -- Socket编程
- .Net下的Socket编程(c#)(一)
- linux环境下C编程(一)
- Linux下Socket网络接口编程(C++)
- Linux下Socket网络编程(C/S)
- Linux C下socket编程API简介
- Linux下C语言socket编程
- 民数记研读1——于宏洁
- Gnuplot使用技巧:线和点的种类(Line and Point Types)
- 如何把带有文字的网址转换成%%E7%BE%8E%E5%B0%91%E5%A5%B3&
- 堆排序算法
- javaWeb定时任务的一种实现方式
- C++服务器(一):了解Linux下socket编程
- 如何使用Xcode7软件添加NTL库并运行C++程序。
- 欧拉项目第四题 Largest palindrome product
- Java反射之gettter和setter方法
- Android Hook神器——XPosed入门(登陆劫持演示)
- Android Studio使用教程(二)
- 民数记研读2——于宏洁
- android开发中源生代码向JS中传值问题
- linux Qt无法自动加载数据库驱动