读书人

求LINUX上C++ socket的视频教程

发布时间: 2012-09-08 10:48:07 作者: rapoo

求LINUX下C++ socket的视频教程
求LINUX下C++ socket的视频教程
求LINUX下C++ socket的视频教程

最好是视频教程

如果是书和资料也可以

先谢谢大家了

[解决办法]
linux 下的网络编程初步
1)第一个就是头文件的添加
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
大体上面几个头文件就可以完成一次基本的客户端服务器交互了。具体每个头文件的重要还
不是很清晰,但是可以通过查询得知。
特别就是<errno.h>中的错误处理函数挺好用的 但是还是要不是很了解。。
2)数据类型
struct sockaddr
{
unsigned short sa_family; //地址族, 一般为 AF_INET
char sa_data[14]; //14 字节的协议地址
}
struct sockaddr_in
{
short int sin_family; //地址族
unsigned short int sin_port; //端口号
struct in_addr in_addr; //ip 地址
unsigned char sin_zero[8]; //填充
}
通常所定义 sockaddr_in 然后再转换成sockaddr 进行地址传输
几个函数
·htonl():把32 位值从主机字节序转换成网络字节序
·htons():把16 位值从主机字节序转换成网络字节序
·ntohl():把32 位值从网络字节序转换成主机字节序
·ntohs():把16 位值从网络字节序转换成主机字节序
至于 ip 地址转换
inet_addr("127.0.0.1");
还有一个就是通过主机地址来解析的
gethostbyname 具体怎么用可以去查下
然后自己感觉 ip 转换函数都是在
inet_XX 后面的。。。
典型的定义本机地址。。。
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(8000);
//my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
my_addr.sin_addr.s_addr=INADDR_ANY;
3)常用函数
1 socket()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:
int socket(int domain, int type, int protocol)
domain: 协议类型,一般为AF_INET
type: socket 类型
protocol:用来指定socket 所使用的传输协议编号,通常设为0 即可
注释:
(1)常用的Socket 类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket
(SOCK_DGRAM)。流式是一种面向连接的 Socket,针对于面向连接的TCP 服务应用;
数据报式Socket 是一种无连接的Socket,对应于无连接的UDP 服务应用
(2)协议类型 AF_INET PF_INET 貌似没有什么区别
AF 表示ADDRESS FAMILY 就是地址族
PF 表示PROTOCL FAMILY 就是协议族
2 bind()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
sockfd: socket 描述符
my_addr:是一个指向包含有本机ip 地址和端口号等信息的sockaddr类型的指针
addrlen:常被设为sizeof(struct sockaddr)
注释:
更加普遍的使用方式是:
int socketID;
struct sockaddr_in my_addr;
//...
bind(socketID,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
3 connect()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
sockfd: 目的服务器的socket 描述符
serv_addr:包含目的机器ip 地址和端口号的指针
addrlen:sizeof(struct sockaddr)
注释:
貌似addrlen 可以用 socklen_t 类型。但是用int 也是没有问题的
4 listen()
头文件:
#include <sys/socket.h>
函数原型:
int listen(int sockfd, int backlog);
sockfd:socket()系统调用返回的socket 描述符
backlog:指定在请求队列中的最大请求数,进入的连接请求将在队列中等待
accept()它们。
5 accept()
头文件:
#include <sys/types.h>
#inlcude <sys/socket.h>
函数原型:
int accept(int sockfd, void *addr, int addrlen)
sockfd:是被监听的socket 描述符
addr:通常是一个指向sockaddr_in 变量的指针,该变量用来存放提出连接请求
服务的主机的信息
addrlen:sizeof(struct sockaddr_in)
注释:
这里我觉得很有问题,因为我在编译的时候使用的下面的构造
struct sockaddr_in client_addr;
socklen_t size=sizeof(struct sockaddr);
client=accept(socketID,(struct sockaddr*)&client_addr,&size);
而使用上面的构造的时候:
编译的时候就会出错。。。
6 send()
头文件:
#include <sys/socket.h>
函数原型:
int send(int sockfd, const void *msg, int len, int flags);
sockfd:用来传输数据的socket 描述符
msg:要发送数据的指针
flags: 0
7 recv()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:
int recv(int sockfd, void *buf, int len, unsigned int flags)
sockfd:接收数据的socket 描述符
buf:存放数据的缓冲区
len:缓冲的长度
flags:0
8 sendto()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:


int sendto(int sockfd, const void *msg, int len, unsigned int flags, const
struct sockaddr *to, int tolen);
9 recvfrom()
头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数原型:
int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct
sockaddr *from, int fromlen)
10 read() write()
int read(int fd, char *buf, int len)
int write(int fd, char *buf, int len)
11 shutdown()
close(sockfd)
int shutdown(int sockfd, int how)
4)代码
服务器端:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in my_addr;
int socketID=socket(AF_INET,SOCK_STREAM,0);
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(8000);
//my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
my_addr.sin_addr.s_addr=INADDR_ANY;
bind(socketID,(struct sockaddr*)(&my_addr),sizeof(struct sockaddr));
printf("Wait For being connected!"n");
int client;
listen(socketID,20);
struct sockaddr_in client_addr;
socklen_t size=sizeof(struct sockaddr);
client=accept(socketID,(struct sockaddr*)&client_addr,&size);
printf("ONE Connect!"n");
char *msg="Hello";
int len =strlen(msg);
printf("%d"n",len);
int suc=send(client,msg,len,0);
if(suc<0)
printf("MSG send error!,Error Marker is %d, Error msg is%s
"n",errno,strerror(errno));
else
printf("MSG Send"n");
return 0;
}

[解决办法]
客户端:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
struct sockaddr_in server_addr;
int socketID;
socketID=socket(AF_INET,SOCK_STREAM,0);
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8000);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
int size=sizeof(struct sockaddr);
if(connect(socketID,(struct sockaddr*)&server_addr,size)<0)
printf("Connetct error!"n");
else
printf("Connect successed!"n");
char msg[30];
recv(socketID,msg,30,0);
int msgLen=strlen(msg);
printf("%d"n",msgLen);
printf("%s"n",msg);
char ss[]="1230faflg";
if(send(socketID,ss,10,0)<0) printf("Send Error!"n");
return 0;
}
代码实现的功能很少,主要就是测试一下 linux 下的网络连接函数怎么用才行。
模型都是很简单的 但是用起来是需要功力的
PS:大部分的内容都是来源网络,最近才开始使用linux 平台。整理了下内容,加深下自
己的理解。
setsockopt 设置socket 详细用法
1.closesocket(一般不会立即关闭而经历TIME_WAIT 的过程)后想继续重用该
socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const
char*)&bReuseaddr,sizeof(BOOL));
2. 如果要已经处于连接状态的 soket 在调用closesocket 后强制关闭,不经历
TIME_WAIT 的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const
char*)&bDontLinger,sizeof(BOOL));
3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1 秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char
*)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char
*)&nNetTimeout,sizeof(int));
4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket 缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688 字节(约为8.5K);在实际的过程中发送数

和接收数据量比较大,可以设置socket 缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K


setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const
char*)&nSendBuf,sizeof(int));
5. 如果在发送数据的时,希望不经历由系统缓冲区到 socket 缓冲区的拷贝而影响
程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char
*)&nZero,sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket 缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
7.一般在发送UDP 数据报的时候,希望该socket 发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const
char*)&bBroadcast,sizeof(BOOL));
8.在client 连接服务器过程中,如果处于非阻塞模式下的socket 在connect()的过程中

以设置 connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const
char*)&bConditionalAccept,sizeof(BOOL));
9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),
以前我们
一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置
让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗
留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5 秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const
char*)&m_sLinger,sizeof(linger));
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////
设置套接口的选项。
#include <winsock.h>
int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
const char FAR* optval, int optlen);
s:标识一个套接口的描述字。
level:选项定义的层次;目前仅支持SOL_SOCKET 和IPPROTO_TCP 层次。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval 缓冲区的长度。
注释:
setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上
存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如
加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。
有两种套接口的选项:一种是布尔型选项,允许或禁止一种特性;另一种是整形或结构
选项。允许一个布尔型选项,则将optval 指向非零整形数;禁止一个选项optval 指向一
个等于零的整形数。对于布尔型选项,optlen 应等于sizeof(int);对其他选项,optval
指向包含所需选项的整形数或结构,而optlen 则为整形数或结构的长度。SO_LINGER 选
项用于控制下述情况的行动:套接口上有排队的待发送数据,且closesocket()调用已执行。
参见closesocket()函数中关于SO_LINGER 选项对closesocket()语义的影响。应用程
序通过创建一个linger 结构来设置相应的操作特性:
struct linger {
int l_onoff;
int l_linger;
};
为了允许SO_LINGER,应用程序应将l_onoff 设为非零,将l_linger 设为零或需要的
超时值(以秒为单位),然后调用setsockopt()。为了允许SO_DONTLINGER(亦即
禁止SO_LINGER),l_onoff 应设为零,然后调用setsockopt()。
缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。但有
时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一确定,所以只要
远端地址不同,两个套接口与一个地址捆绑并无大碍。为了通知WINDOWS 套接口实现不
要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑,应用程序可在bind()
调用前先设置SO_REUSEADDR 选项。请注意仅在bind()调用时该选项才被解释;故此
无需(但也无害)将一个不会共用地址的套接口设置该选项,或者在bind()对这个或其他
套接口无影响情况下设置或清除这一选项。
一个应用程序可以通过打开SO_KEEPALIVE 选项,使得WINDOWS 套接口实现在TCP
连接情况下允许使用“保持活动”包。一个WINDOWS 套接口实现并不是必需支持“保持活
动”,但是如果支持的话,具体的语义将与实现有关,应遵守RFC1122“Internet 主机要求
-通讯层”中第4.2.3.6 节的规范。如果有关连接由于“保持活动”而失效,则进行中的任何
对该套接口的调用都将以WSAENETRESET 错误返回,后续的任何调用将以
WSAENOTCONN 错误返回。
TCP_NODELAY 选项禁止Nagle 算法。Nagle 算法通过将未确认的数据存入缓冲区直
到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。但对于某些应用来
说,这种算法将降低系统性能。所以TCP_NODELAY 可用来将此算法关闭。应用程序编写
者只有在确切了解它的效果并确实需要的情况下,才设置TCP_NODELAY 选项,因为设置
后对网络性能有明显的负面影响。TCP_NODELAY 是唯一使用IPPROTO_TCP 层的选项,
其他所有选项都使用SOL_SOCKET 层。
如果设置了SO_DEBUG 选项,WINDOWS 套接口供应商被鼓励(但不是必需)提供输
出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。
setsockopt()支持下列选项。其中“类型”表明optval 所指数据的类型。
选项 类型意义
SO_BROADCAST BOOL 允许套接口传送广播信息。
SO_DEBUG BOOL 记录调试信息。
SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将
SO_LINGER 的l_onoff 元素置为零。
SO_DONTROUTE BOOL 禁止选径;直接传送。
SO_KEEPALIVE BOOL 发送“保持活动”包。
SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留。
SO_OOBINLINE BOOL 在常规数据流中接收带外数据。
SO_RCVBUF int 为接收确定缓冲区大小。
SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind())。
SO_SNDBUF int 指定发送缓冲区大小。
TCP_NODELAY BOOL 禁止发送合并的Nagle 算法。
setsockopt()不支持的BSD 选项有:


选项名 类型意义
SO_ACCEPTCONN BOOL 套接口在监听。
SO_ERROR int 获取错误状态并清除。
SO_RCVLOWAT int 接收低级水印。
SO_RCVTIMEO int 接收超时。
SO_SNDLOWAT int 发送低级水印。
SO_SNDTIMEO int 发送超时。
SO_TYPE int 套接口类型。
IP_OPTIONS 在IP 头中设置选项。
返回值:
若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR 错误,应用
程序可通过WSAGetLastError()获取相应错误代码。
错误代码:
WSANOTINITIALISED:在使用此API 之前应首先成功地调用WSAStartup()。
WSAENETDOWN:WINDOWS 套接口实现检测到网络子系统失效。
WSAEFAULT:optval 不是进程地址空间中的一个有效部分。
WSAEINPROGRESS:一个阻塞的WINDOWS 套接口调用正在运行中。
WSAEINVAL:level 值非法,或optval 中的信息非法。
WSAENETRESET:当SO_KEEPALIVE 设置后连接超时。
WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM 类型的套接口不
支持SO_BROADCAST选项,SOCK_DGRAM类型的套接口不支持SO_DONTLINGER 、
SO_KEEPALIVE、SO_LINGER 和SO_OOBINLINE 选项。
WSAENOTCONN:当设置SO_KEEPALIVE 后连接被复位。
WSAENOTSOCK:描述字不是一个套接口。
参见:
bind(), getsockopt(), ioctlsocket(), socket(), WSAAsyncSelect().
copy from:http://blog.csdn.net/qinmi/archive/2007/03/07/1523081.aspx
阻塞和非阻塞
阻塞函数在完成其指定的任务以前不允许程序调用另一个函数。例如,程序执行一个读
数据的函数调用时,在此函数完成读操作以前将不会执行下一程序语句。当服务器运行到
accept 语句时,而没有客户连接服务请求到来,服务器就会停止在accept 语句上等待连
接服务请求的到来。这种情况称为阻塞(blocking)。而非阻塞操作则可以立即完成。比如,
如果你希望服务器仅仅注意检查是否有客户在等待连接,有就接受连接,否则就继续做其他
事情,则可以通过将Socket 设置为非阻塞方式来实现。非阻塞socket 在没有客户在等待
时就使accept 调用立即返回。
#include
#include
……
sockfd = socket(AF_INET,SOCK_STREAM,0);
fcntl(sockfd,F_SETFL,O_NONBLOCK);
……
通过设置socket 为非阻塞方式,可以实现"轮询"若干Socket。当企图从一个没有数
据等待处理的非阻塞Socket 读入数据时,函数将立即返回,返回值为-1,并置errno 值
为EWOULDBLOCK。但是这种"轮询"会使CPU 处于忙等待方式,从而降低性能,浪费系
统资源。而调用select()会有效地解决这个问题,它允许你把进程本身挂起来,而同时使
系统内核监听所要求的一组文件描述符的任何活动,只要确认在任何被监控的文件描述符上
出现活动,select()调用将返回指示该文件描述符已准备好的信息,从而实现了为进程选出
随机的变化,而不必由进程本身对输入进行测试而浪费CPU 开销。Select 函数原型为:
int select(int numfds,fd_set *readfds,fd_set *writefds,
fd_set *exceptfds,struct timeval *timeout);
其中readfds、writefds、exceptfds 分别是被select()监视的读、写和异常处理的
文件描述符集合。如果你希望确定是否可以从标准输入和某个socket 描述符读取数据,你
只需要将标准输入的文件描述符0 和相应的sockdtfd 加入到readfds 集合中;numfds
的值是需要检查的号码最高的文件描述符加1,这个例子中numfds 的值应为sockfd+1;
当select 返回时,readfds 将被修改,指示某个文件描述符已经准备被读取,你可以通过
FD_ISSSET()来测试。为了实现fd_set 中对应的文件描述符的设置、复位和测试,它提
供了一组宏:
FD_ZERO(fd_set *set)----清除一个文件描述符集;
FD_SET(int fd,fd_set *set)----将一个文件描述符加入文件描述符集中;
FD_CLR(int fd,fd_set *set)----将一个文件描述符从文件描述符集中清除;
FD_ISSET(int fd,fd_set *set)----试判断是否文件描述符被置位。
Timeout 参数是一个指向struct timeval 类型的指针,它可以使select()在等待
timeout 长时间后没有文件描述符准备好即返回。struct timeval 数据结构为:
struct timeval {
int tv_sec; /* seconds */
int tv_usec; /* microseconds */
};
[解决办法]

探讨

客户端:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
struct sockaddr_in server_addr;
int socketID;
socketID=socket……

[解决办法]
最好还是看书,unix网络编程

读书人网 >C++

热点推荐