socket操作
1.1 创建socket
int socket(int domain, int type, int protocol);
domain: 确定通信的特性
AF_INET IPv4因特网域
AF_INET6 IPv6因特网域
AF_UNIX UNIX域
AF_UNSPEC 未指定
type: 指定套接字的类型
SOCK_DGRAM 长度固定的、无连接的不可靠报文传递
SOCK_RAW IP协议的数据报接口(POSIX.1中可选)
SOCK_SEQPACKET 长度固定、有序、可靠的面向连接报文传递
SOCK_STREAM 有序、可靠、双向的面向连接字节流
protocol参数通常是0,表示按给定的域和套接字类型选择默认协议。当同一域和套接字类型支持多个协议的时候,可以使用protocol参数选择一个特定的协议。
AF_INET通信域中套接字类型SOCK_STREAM的默认协议是TCP(传输控制协议)
AF_INET通信与中套接字类型SOCK_DGRAM的默认协议是UDP(用户数据报协议)
1.2 绑定地址(server)
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
sockfd: 要绑定的套接字
my_addr: 地址结构体
addrlen: 结构体长度,通常为sizeof(my_addr)
1.2.1 struct sockaddr
该结构体定义了地址信息
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};
1.2.2 网络字节转换
网络中的数据格式为大端,所以需要将小端存储的数据转换成为大端存储,一下为网络字节序和本地字节序(小端)之间转换函数
uint32_t htonl(uint32_t hostint32); /// host to net long(uint32_t)
uint16_t htons(uint16_t hostint16); /// host to net short(uint16_t)
uint32_t ntohl(uint32_t netint32); /// net to host long(uint32_t)
uint16_t ntohs(uint16_t netint16); /// net to host short(uint16_t)
1.2.3 inet_pton
int inet_pton(int af, const char *src, void *dst);
将字符串类型的地址转换成为struct sockaddr_in::sin_addr类型
af: 通信特性
src: 地址字符串
dst: truct sockaddr_in::sin_addr类型,长度必需为sizeof(struct in_addr).
1.2.4 查询地址
#include
struct hostent *gethostent(void); ///(打开主机数据文件)返回struct hostent
void endhostent(void); /// 关闭打开的主机数据 文件
void sethostent(int stayopen); /// 打开主机数据 文件
struct hostent {
char *h_name; /// 主机名
char **h_aliases;
int h_addrtype;
int h_length;
char **h_addr_list;
. . .
};
设置地址的例子:
struct sockaddr_in laddr;
laddr.sin_family = AF_INET;
laddr.sin_port = hotns(atoi(SERVERPORT));
inet_pton(AF_INET, "0.0.0.0", &laddr.sin_addr);
1.3 建立连接(client)
int connect(int sockfd , const struct sockaddr* my_addr , socket_t addrlen );
sockfd: 套接字
my_addr: 想连接的服务器的地址
addrlen: 地址结构的长度,通常为sizeof(my_addr)
1.4 服务器宣告可以接受连接请求 listen
int listen(int sockfd, int backlog);
backlog: 该进程最大的入队连接请求数
1.5 获得连接请求并建立连接 accept
int accept(int sockfd, struct sockaddr* my_addr , socket_t *addrlen );
my_addr: 用户地址
addrlen: 用户地址长度
1.6 发数据(client)
ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
sockfd: 套接字
buf: 要发送数据的buf
nbytes: buf长度
flags: 发送标识
MSG_DONTROUTE: 勿将数据路由出本地网络
MSG_DONTWAIT: 允许非阻塞操作
MSG_EOR: 如果协议支持,此为记录结束
MSG_OOB: 如果协议支持,发送外带数据
1.7 收数据(server)
ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
sockfd: 套接字
buf: 接收数据的buf
nbytes: buf长度
flags: 发送标识
MSG_OOB: 如果协议支持,接收外带数据
MSG_PRRK: 返回报文内容而不真正取走报文
MSG_TRUNC: 即使报文被截断,要求返回的是报文的实际长度
MSG_WAITALL: 等待直到所有的数据可用(仅SOCK_STREAM)
mysocket.h
#ifndef MYSOCKET_H_INCLUDED
#define MYSOCKET_H_INCLUDED
#include
#include
#include
#include
#define SERVERPORT "1234"
#define SERVERIP "127.0.0.1"
#define MAXBACKLOG 10
#define MAXIPSIZE 20
#define BUFMAXSIZE 1024*1024
#define WRITEFILEPATH "./recvFile"
#define READFILEPATH "./a.tgz"
using namespace std;
#endif // MYSOCKET_H_INCLUDED
client.cpp
#include "mysocket.h"
int main()
{
int iRet = 0;
int sockFd = 0;
struct sockaddr_in serverAddr;
sockFd = socket(AF_INET, SOCK_STREAM, 0);
char sendBuf[BUFMAXSIZE];
if (sockFd < 0) {
cout << "socket is error" << endl;
} else {
cout << "socket is ok" << endl;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET, SERVERIP, &serverAddr.sin_addr);
iRet = connect(sockFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if (iRet < 0) {
cout << "connect is error." << endl;
} else {
cout << "connect is ok." << endl;
}
FILE *rfp = fopen(READFILEPATH, "rb+");
while(1) {
iRet = fread(sendBuf, 1, BUFMAXSIZE, rfp);
cout << "fork:fread ret = " << iRet << endl;
if (iRet < 0) {
cout << "fread is error" << endl;
break;
}
iRet = send(sockFd, sendBuf, iRet, 0);
if (iRet < BUFMAXSIZE) {
cout << "fread is eof" << endl;
break;
}
}
fclose(rfp);
return 0;
}
server.cpp
#include "mysocket.h"
int main()
{
int iRet = 0;
int sockFd = 0;
struct sockaddr_in serverAddr, clientAddr;
socklen_t clientLen = 0;
char clientIP[MAXIPSIZE];
char recvBuf[BUFMAXSIZE];
sprintf(recvBuf, "rm %s", WRITEFILEPATH);
system(recvBuf);
memset(recvBuf, 0, BUFMAXSIZE);
int recvLen = 0;
FILE *fp = NULL, *wfp = NULL;
sockFd = socket(AF_INET, SOCK_STREAM, 0); /// create socket
if (sockFd < 0) {
cout << "socket is error" << endl;
} else {
cout << "socket is ok" << endl;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET, "0.0.0.0", &serverAddr.sin_addr);
iRet = bind(sockFd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); /// bind addr
if (iRet < 0) {
cout << "bind is error." << endl;
} else {
cout << "bind is ok." << endl;
}
iRet = listen(sockFd, MAXBACKLOG); /// listen
if (iRet < 0) {
cout << "listen is error." << endl;
} else {
cout << "listen is ok." << endl;
}
int newSd;
while(1) {
newSd = accept(sockFd, (struct sockaddr*)&clientAddr, &clientLen);
if (newSd < 0) {
cout << "accept is error : iRet = " << iRet << endl;
break;
}
inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, MAXIPSIZE);
cout << "client: " << clientIP << " : " << ntohs(clientAddr.sin_port) << " is connected" << endl;
if (fork() == 0) {
wfp = fopen(WRITEFILEPATH, "ab+");
fp = fdopen ( newSd, "r+" );
while (1) {
iRet = fread ( recvBuf, 1, BUFMAXSIZE, fp );
if (iRet <= 0) {
cout << "recv is done" << endl;
break;
}
fwrite(recvBuf, 1, iRet, wfp);
}
fclose(fp);
fclose(wfp);
}
sleep(1);
}
return 0;
}