套接字是TCP/IP网络编程中的基本操作单元,不同主机的进程之间的相互通信的端点。
socket是在应用层和传输层之间的一个抽象层,它把TCP/IC层复杂的操作抽象为几个简单的接口,供应用层调用已实现进程在网络中通信。
B/S(Browser/Server,浏览器/服务器)架构,用户只需要浏览器就行,主要逻辑在服务器完成,减轻了客户端的升级和维护的工作量。
C/S(Client/Server,客户机/服务器)架构,客户端和服务端安装不同应用软件,客户端软件安装或升级比较复杂,维护成本大,可以充分利用两端的硬件能力,较为合理的分配任务。
客户机和服务器间的通信过程:
(1)客户机向服务器提出一个请求。
(2)服务器收到客户机的请求,进行分析处理。
(3)服务器将处理的结果返回给客户机。
#include
//字符串IP地址转换为网络字节序存储在addr中,并返回该网络字节序表示的无符号整数。
//失败:返回0
int inet_aton(const char *IP, struct in_addr *addr);
//返回网络字节序
//uint32,失败-1
in_addr_t inet_addr(const char* cp);
//及时复制返回的字符串
char *inet_ntoa(struct in_addr in);
#include
#include
#include
int main()
{
char IP[] = "159.12.8.109";
in_addr address;
int number = inet_aton(IP, &address);//将点分十进制的IP地址转化为二进制的网络字节序
if(number == 0)
{
std::cerr<<"error IP!";
exit(1);
}
std::cout << number << std::endl;
std::cout << inet_ntoa(address) << std::endl;//将网络字节序地址转化为点分十进制表示形式
return 0;
}
#include
#include
int main()
{
in_addr_t dwIP = inet_addr("172.16.2.6");
struct in_addr ia;
ia.s_addr = dwIP;
printf("ia.s_addr = %#x\n", ia.s_addr);
printf("real_ip = %s\n", inet_ntoa(ia));
return 0;
}
(1)流套接字(SOCK_STREAM)
用于提供面向连接的、可靠的数据传输服务,无数据边界(收发次数不一致),可保证数据能够无差别、无重复发送,并按顺序接收(因为使用了传输控制协议即TCP)。
(2)数据报套接字(SOCK_DGRAM)
提供无连接的服务,不保证数据传输的可靠性,有数据边界(数据报收发次数一致),数据传输过程中可能丢失或重复,且无法保证接收数据有序。(使用UDP传输)
(3)原始套接字(SOCK_RAW)
允许对较低层次的协议(IP、ICMP等)直接访问,常用于检验新的协议实现,或者访问现有服务中配置的新设备。
能够控制网络底层传输机制,所以可以应用原始套接字操纵网络层和传输层应用。接收ICMP、IGMP协议包,接收TCP/IP栈不能处理的IP包,发送自定义报头或自定义协议的IP包。
能够读写内核没有处理的IP数据报。
包含IP地址和端口信息,识别主机及进程。
表示大多数网络地址,用于socket API函数中。
struct sockaddr{
sa_family_t sa_family;
char sa_data[14];
};
sa_family_t:地址族或协议族类型
sa_data:存放具体的地址数据(IP和端口)
协议族 | 地址的含义和长度 |
---|---|
PF_INET | 32位IPV4地址和16位端口号,共6字节 |
PF_INET6 | 128位IPv6地址、16位端口号、32位流标识和32位范围ID,共26字节 |
PF_UNIX | 文件全路劲名,最大长度可达108字节 |
不同协议族定义的不同socket地址结构体,各个信息用不同字段表示。
一般强制转换为通用地址结构使用。
/* 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)];
};
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
#if !__USE_KERNEL_IPV6_DEFS
/* Ditto, for IPv6. */
struct sockaddr_in6
{
__SOCKADDR_COMMON (sin6_);
in_port_t sin6_port; /* Transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};
#endif /* !__USE_KERNEL_IPV6_DEFS */
#if !__USE_KERNEL_IPV6_DEFS
/* IPv6 address */
struct in6_addr
{
union
{
uint8_t __u6_addr8[16];
uint16_t __u6_addr16[8];
uint32_t __u6_addr32[4];
} __in6_u;
#define s6_addr __in6_u.__u6_addr8
#ifdef __USE_MISC
# define s6_addr16 __in6_u.__u6_addr16
# define s6_addr32 __in6_u.__u6_addr32
#endif
};
#endif /* !__USE_KERNEL_IPV6_DEFS */
#include
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
//成功0,失败-1
//socklen_t addrlen = sizeof(struct sockaddr_in);
getsockname获取本地套接字地址的情况:
#include
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);
//成功0,失败-1
//socklen_t addrlen = sizeof(struct sockaddr_in);
#include
#include
#include
#include
#include
int main()
{
int sfp = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sfp)
{
printf("socket() fail!\n");
return -1;
}
printf("socket() ok!\n");
char on = 1;
setsockopt(sfp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
struct sockaddr_in serv = {0};
int serv_len = sizeof(serv);
printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));
getsockname(sfp, (struct sockaddr *)&serv, (socklen_t *)&serv_len);
printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));
unsigned short portnum = 10051;
struct sockaddr_in s_add;
memset(&s_add, 0, sizeof(struct sockaddr_in));
s_add.sin_family = AF_INET;
s_add.sin_addr.s_addr = inet_addr("127.0.0.1");
s_add.sin_port = htons(portnum);
if (-1 == bind(sfp, (struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
{
printf("bind() fail: %d!\n", errno);
return -1;
}
printf("bind() ok!\n");
getsockname(sfp, (struct sockaddr *)&serv, (socklen_t *)&serv_len);
printf("ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));
return 0;
}
大端字节序Big Endian(网络字节序)
底地址存放高字节
uint32_t主机字节序转网络字节序
htonl
uint16_t主机字节序转网络字节序
htons
uint32_t网络字节序转主机字节序
ntohl
uint16_t网络字节序转主机字节序
ntohs
#include
using namespace std;
int main()
{
int nNum = 0x12345678;
char *p = (char *)&nNum;
if (*p == 0x12)
cout << "This machine is big endian." << endl;
else
cout << "This machine is small endian." << endl;
return 0;
}
协议族
不同协议的集合,宏以PF_开头,PROTOCOL FAMILY
地址族
协议族所使用的地址集合(不同网络协议使用不同网络地址),宏以AF_开头,Address Family
地址族和协议族的值一样,都用来标识不同的一套协议。
客户端编程步骤:
一、创建套接字,socket函数
二、向服务器发出请求连接,connect函数
三、同服务器端通信,send或recv函数,
四、通信结束关闭,closesocket函数
#include
#include
#include
#include
#include
创建套接字,并分配系统资源
int socket(int domain, int type, int protocol);
//AF_INET
//SOCK_STREAM, SOCK_DGRAM, SOCK_RAW
//IPPROTO_TCP, IPPROTO_UDP, 0
//默认都是阻塞
本地地址信息关联到套接字上。
int bind(int sockfd, const struct* addr, socklen_t addrlen);
//成功0,失败-1,errno获取错误码
sockaddr_in in;
in_addr_t ip = inet_addr("192.168.13.25");
if(ip != -1)
in.sin_addr.s_addr = ip;
//#define INADDR_ANY ((in_addr_t) 0x00000000)
in.sin_addr.s_addr = htonl(INADDR_ANY);
//errno,98,端口占用、未释放或程序未正常结束
套接字处于监听状态。
int listen(int sockfd, int backlog);
//成功0,失败-1
从监听套接字的客户连接请求队列获取客户端请求,并创建新的套接字来和客户端通信。
int accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen);
//失败-1
请求与监听套接字建立连接。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
//成功0,失败-1
非阻塞时,可设置连接超时时间,通过error中EINRPOCESS(Operation now in progress)判断。
发送数据,复制到套接字的发送缓冲区。
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//成功返回发送拷贝字节数,对方关闭返回0,错误-1
TCP有发送缓冲区,UDP无发送缓冲区。
非阻塞,可利用error变量EAGAIN
send用于有连接的套接字。
sendto和sendmsg用于有或无连接的套接字。
接收数据.
ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
//成功返回接收字节数,对方关闭返回0,错误-1,errno是EINTR、EWOULDBLOCK或EAGAIN时连接正常
recvfrom也能接收数据。
关闭套接字
#include
int close(int fd);
//成功0,失败-1
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
char on = 1;
setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
struct sockaddr_in addrSrv;
memset(&addrSrv, 0, sizeof(struct sockaddr_in));
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
if (-1 == bind(sockSrv, (struct sockaddr *)&addrSrv, sizeof(struct sockaddr)))
{
printf("bind() fail: %d!\n", errno);
return -1;
}
const int len = sizeof(struct sockaddr_in);
struct sockaddr_in serv;
getsockname(sockSrv, (struct sockaddr *)&serv, (socklen_t *)&len);
printf("server has started, ip=%s, port=%d\n", inet_ntoa(serv.sin_addr), ntohs(serv.sin_port));
listen(sockSrv, 5);
struct sockaddr_in addrClient;
while (1)
{
printf("--------wait for client-----------\n");
int sockConn = accept(sockSrv, (struct sockaddr *)&addrClient, (socklen_t *)&len);
char sendBuf[100];
sprintf(sendBuf, "Welcome client(%s: %d) to Server!", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));
send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
char recvBuf[100];
recv(sockConn, recvBuf, 100, 0);
printf("Receive client's msg: %s\n", recvBuf);
close(sockConn);
/*
puts("continue to listen?(y/n)");
char ch[2];
scanf("%s", ch, 2);
if (ch[0] != 'y')
break;
*/
}
close(sockSrv);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
int main()
{
int sockClient = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
int err = connect(sockClient, (struct sockaddr *)&addrSrv, sizeof(struct sockaddr));
if (-1 == err)
{
printf("Failed to connect to the server.Please check whether the server is started\n");
return 0;
}
char recvBuf[100] = {0};
recv(sockClient, recvBuf, 100, 0);
printf("receive server's msg: %s\n", recvBuf);
char msg[] = "hi,server";
send(sockClient, msg, strlen(msg) + 1, 0);
close(sockClient);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_SIZE 512
unsigned long GetTickCount()
{
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
return 0;
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
int main()
{
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("192.168.0.88");
server_address.sin_port = htons(13334);
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
long t1 = GetTickCount();
int ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));
if (ret == -1)
{
long t2 = GetTickCount();
printf("connect() failed: %d\n", ret);
printf("time used: %ldms\n", t2 - t1);
if (errno == EINPROGRESS)
printf("unblock mode ret code...\n");
}
else
printf("ret code is: %d\n", ret);
close(sock);
return 0;
}
应用缓冲区和TCP套接字缓冲区(内核缓冲区)。
一、字节流,无消息边界。
二、send后并不立即发送数据,内核控制。
三、数据发送速度,网络状态决定。
四、控制数据真实发送,网络状态决定。
五、recv时并不知道真实已接收多少数据。
假设调用两次send,发送数据A和数据B。(send(A),send(B)),真实发送情况:
一、网络情况良好,未受发送窗口、拥塞窗口和TCP最大传输单元影响,A、B变成两个数据段发送。
二、网络不好,发送A被延迟,A、B数据合并,且长度未超过窗口大小和最大传输单元。AB合并发送一次。
三、网络不好,发送A被延迟,A、B数据合并,且长度超过窗口大小或最大传输单元。AB合并发送(AB1、B2)。
四、网络不好,发送A被延迟,A、B数据合并,且长度超过窗口大小或最大传输单元。AB合并发送(A1、A2B)。
五、接收窗口小,AB分成多份发送。
六、发送错误,失败。
send与实际发送次数无关,send与recv次数无关。
接收到全部数据后断开连接,通过recv返回0判断发送方数据发送完毕。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 300
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
assert(sockSrv >= 0);
char on = 1;
setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
listen(sockSrv, 5);
const int len = sizeof(SOCKADDR);
SOCKADDR_IN addrClient;
while (1)
{
printf("--------wait for client-----------\n");
int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);
char sendBuf[100] = "";
for (int i = 0; i < 10; i++)
{
memset(sendBuf, 0, sizeof(sendBuf));
sprintf(sendBuf, "N0.%d Welcome to the server. What is 1 + 1 = ? (client IP: %s, client Port: %d)\n", i + 1, inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));
send(sockConn, sendBuf, strlen(sendBuf), 0);
}
int iRes = shutdown(sockConn, SHUT_WR);
if (iRes == -1)
{
printf("shutdown failed with error: %d\n", errno);
close(sockConn);
return 1;
}
char recvBuf[BUF_LEN];
do
{
iRes = recv(sockConn, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("Recv %d bytes.\n", iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
printf("The client has closed the connection.\n");
}
else
{
printf("recv failed with error: %d\n", errno);
close(sockConn);
return 1;
}
} while (iRes > 0);
close(sockConn);
/*
puts("Continue monitoring?(y/n)");
char ch[2];
scanf("%s", ch, 2);
if (ch[0] != 'y')
break;
*/
}
close(sockSrv);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 300
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
int main()
{
int sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
if (-1 == err)
{
printf("Failed to connect to the server. Please check whether the server is started\n");
return 0;
}
char recvBuf[BUF_LEN];
int iRes;
do
{
iRes = recv(sockClient, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nRecv %d bytes:", iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("The server has closed the send connection.\n");
}
else
{
printf("recv failed:%d\n", errno);
close(sockClient);
return 1;
}
} while (iRes > 0);
char sendBuf[100];
for (int i = 0; i < 10; i++)
{
memset(sendBuf, 0, sizeof(sendBuf));
sprintf(sendBuf, "N0.%d I'm the client, 1+1=2\n", i + 1);
send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);
}
puts("Sending data to the server is completed.");
close(sockClient);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 300
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
assert(sockSrv >= 0);
char on = 1;
setsockopt(sockSrv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
listen(sockSrv, 5);
const int len = sizeof(SOCKADDR);
SOCKADDR_IN addrClient;
char sendBuf[111];
char recvBuf[BUF_LEN];
while (1)
{
printf("--------wait for client-----------\n");
int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);
printf("--------client comes-----------\n");
memset(sendBuf, 'a', 111);
for (int cn = 0; cn < 50; cn++)
{
if (cn == 49)
sendBuf[110] = 'b';
send(sockConn, sendBuf, 111, 0);
}
int iRes;
do
{
iRes = recv(sockConn, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nRecv %d bytes:", iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
printf("The client closes the connection.\n");
}
else
{
printf("recv failed with error: %d\n", errno);
close(sockConn);
return 1;
}
} while (iRes > 0);
close(sockConn);
/*
puts("Continue monitoring?(y/n)");
char ch[2];
scanf("%s", ch, 2);
if (ch[0] != 'y')
break;
*/
}
close(sockSrv);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 250
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
int main()
{
int sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
if (-1 == err)
{
printf("Failed to connect to the server:%d\n", errno);
return 0;
}
char recvBuf[BUF_LEN];
int iRes;
int cn = 1;
for (int leftlen = 50 * 111; leftlen > 0; leftlen -= iRes)
{
iRes = recv(sockClient, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
}
/*
int leftlen = 50 * 111;
while (leftlen > BUF_LEN)
{
iRes = recv(sockClient, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
leftlen -= iRes;
}
if (leftlen > 0)
{
iRes = recv(sockClient, recvBuf, leftlen, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
leftlen -= iRes;
}
*/
char sendBuf[100];
memset(sendBuf, 0, sizeof(sendBuf));
sprintf(sendBuf, "Hi, Server, I've finished receiving the data.");
send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);
puts("Sending data to the server is completed");
close(sockClient);
return 0;
}
struct MyData
{
int nLen;
char data[0];
};
struct MyData* p = (struct MyData*)malloc(sizeof(struct MyData)+strlen(str));
#include
#include
#include
using namespace std;
struct MyData
{
int nLen;
char data[0];
};
int main()
{
cout << "Size of MyData: " << sizeof(MyData) << endl;
char str[10] = "123456";
int nLen = sizeof(str);
MyData *myData = (MyData *)malloc(sizeof(MyData) + nLen);
myData->nLen = nLen;
memcpy(myData->data, str, nLen);
cout << "myData's Data is: " << myData->data << endl;
cout << "Size of MyData: " << sizeof(MyData) << endl;
free(myData);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 300
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
struct MyData
{
int nLen;
char data[0];
};
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
bind(sockSrv, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
listen(sockSrv, 5);
SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR);
int cn = 5550;
struct MyData *mydata;
int iRes;
char recvBuf[BUF_LEN];
while (1)
{
printf("--------wait for client-----------\n");
int sockConn = accept(sockSrv, (SOCKADDR *)&addrClient, (socklen_t *)&len);
printf("--------client comes-----------\n");
mydata = (MyData *)malloc(sizeof(MyData) + cn);
mydata->nLen = htonl(cn);
memset(mydata->data, 'a', cn);
mydata->data[cn - 1] = 'b';
send(sockConn, (char *)mydata, sizeof(MyData) + cn, 0);
free(mydata);
do
{
iRes = recv(sockConn, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nRecv %d bytes: ", iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
printf("\nThe client has closed the connection.\n");
}
else
{
printf("recv failed with error: %d\n", errno);
close(sockConn);
return 1;
}
} while (iRes > 0);
close(sockConn);
/*
puts("Continue monitoring?(y/n)");
char ch[2];
scanf("%s", ch, 2);
if (ch[0] != 'y')
break;
*/
}
close(sockSrv);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUF_LEN 250
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
int main()
{
int sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8000);
int err = connect(sockClient, (SOCKADDR *)&addrSrv, sizeof(SOCKADDR));
if (-1 == err)
{
printf("Failed to connect to the server:%d\n", errno);
return 0;
}
int leftlen;
int iRes = recv(sockClient, (char *)&leftlen, sizeof(int), 0);
leftlen = ntohl(leftlen);
printf("Need to receive %d bytes data.\n", leftlen);
char recvBuf[BUF_LEN];
int cn = 1;
for (; leftlen > 0; leftlen -= iRes)
{
if (leftlen < BUF_LEN)
iRes = recv(sockClient, recvBuf, leftlen, 0);
else
iRes = recv(sockClient, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
}
/*
while (leftlen > BUF_LEN)
{
iRes = recv(sockClient, recvBuf, BUF_LEN, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
leftlen -= iRes;
}
if (leftlen > 0)
{
iRes = recv(sockClient, recvBuf, leftlen, 0);
if (iRes > 0)
{
printf("\nNo.%d: Recv %d bytes: ", cn++, iRes);
for (int i = 0; i < iRes; i++)
printf("%c", recvBuf[i]);
printf("\n");
}
else if (iRes == 0)
{
puts("\nThe server has closed the send connection.\n");
}
else
{
printf("recv failed: %d\n", errno);
close(sockClient);
return -1;
}
leftlen -= iRes;
}
*/
char sendBuf[100];
memset(sendBuf, 0, sizeof(sendBuf));
sprintf(sendBuf, "I'm the client. I've finished receiving the data.");
send(sockClient, sendBuf, strlen(sendBuf) + 1, 0);
puts("Sending data to the server is completed");
close(sockClient);
return 0;
}
设置套接字的工作模式(阻塞或非阻塞),获取套接字I/O操作的参数信息。
#include
int ioctl(int fd, int request, ...);
//成功0,失败-1,errno错误码
I/O控制命令request:
int iMode = 0;
ioctl(m_socket, FIONBIO, &iMode); //阻塞模式
int num = 0;
ioctl(0, FIONREAD, &iMode); //标准输入缓冲区字节数
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
unsigned long GetTickCount()
{
struct timeval tv;
if (gettimeofday(&tv, NULL) != 0)
return 0;
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
int main()
{
char ip[] = "192.168.0.88";
in_addr_t dwIP = inet_addr(ip);
int port = 13334;
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = dwIP;
server_address.sin_port = htons(port);
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
long t1 = GetTickCount();
int ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));
printf("connect ret code is: %d\n", ret);
if (ret == -1)
{
long t2 = GetTickCount();
printf("time used: %ldms\n", t2 - t1);
printf("connect() failed...\n");
if (errno == EINPROGRESS)
printf("unblock mode ret code...\n");
}
else
printf("ret code is: %d\n", ret);
int argp = 1;
int res = ioctl(sock, FIONBIO, &argp);
if (-1 == res)
{
printf("Error at ioctlsocket(): %d\n", errno);
return -1;
}
puts("\nAfter setting non blocking mode:");
/*
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = dwIP;
server_address.sin_port = htons(port);
*/
t1 = GetTickCount();
ret = connect(sock, (struct sockaddr *)&server_address, sizeof(server_address));
printf("connect ret code is: %d\n", ret);
if (ret == -1)
{
long t2 = GetTickCount();
printf("time used: %ldms\n", t2 - t1);
if (errno == EINPROGRESS)
printf("unblock mode errno: %d\n", errno);
}
else
printf("ret code is: %d\n", ret);
close(sock);
return 0;
}
设置或获取套接字属性
适用范围或适用对象,有些选项针对特定协议,有些选项适用所有类型套接字。
SO_TYPE
SO_SNDBUF
SO_REUSEADDR
SO_RCVBUF
SO_ERROR
…
#include
#include
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
//成功0,失败-1,errno错误码
//EBADF:sockfd不是有效文件描述符
//EFAULT:optlen太小或optval缓冲区非法
//EINVAL:level未知或非法
//ENOPROTOOPT:选项未知或不被指定协议族支持
//ENOTSOCK:sockfd不是套接字描述符
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1)
{
printf("Error at socket()\n");
return -1;
}
int su = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1)
{
printf("Error at socket()\n");
return -1;
}
int optVal;
int optLen = sizeof(optVal);
if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
printf("Size of stream socket receive buffer: %d bytes\n", optVal);
if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
printf("Size of streaming socket send buffer: %d bytes\n", optVal);
if (getsockopt(su, SOL_SOCKET, SO_RCVBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
printf("Size of datagram socket receive buffer: %d bytes\n", optVal);
if (getsockopt(su, SOL_SOCKET, SO_SNDBUF, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
printf("Size of datagram socket send buffer: %d bytes\n", optVal);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1)
{
printf("Error at socket()\n");
return -1;
}
int optVal;
int optLen = sizeof(optVal);
if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
{
if (SOCK_STREAM == optVal)
printf("The current socket is a stream socket.\n");
else if (SOCK_DGRAM == optVal)
printf("The current socket is a datagram socket.\n");
}
int su = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (su == -1)
{
printf("Error at socket()\n");
return -1;
}
if (getsockopt(su, SOL_SOCKET, SO_TYPE, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
{
if (SOCK_STREAM == optVal)
printf("The current socket is a stream socket.\n");
else if (SOCK_DGRAM == optVal)
printf("The current socket is a datagram socket.\n");
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr SOCKADDR;
int main()
{
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1)
{
printf("Error at socket()\n");
return -1;
}
char on = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
char ip[] = "127.0.0.1";
struct sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(8000);
if (bind(s, (SOCKADDR *)&service, sizeof(service)) == -1)
{
printf("bind failed: %d\n", errno);
return -1;
}
int optVal;
int optLen = sizeof(optVal);
if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&optVal, (socklen_t *)&optLen) == -1)
printf("getsockopt failed: %d", errno);
else
printf("Before listening, The value of SO_ACCEPTCONN: %d, The socket is not listening\n", optVal);
if (listen(s, 100) == -1)
{
printf("listen failed: %d\n", errno);
return -1;
}
if (getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, (char *)&optVal, (socklen_t *)&optLen) == -1)
{
printf("getsockopt failed: %d", errno);
return -1;
}
else
printf("After listening, The value of SO_ACCEPTCONN: %d, The socket is listening\n", optVal);
return 0;
}
#include
#include
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t *optlen);
//成功0,失败-1,errno错误码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct sockaddr SOCKADDR;
int main()
{
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1)
{
printf("Error at socket()\n");
return -1;
}
char on = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
char ip[] = "127.0.0.1";
struct sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr(ip);
service.sin_port = htons(9900);
if (bind(s, (SOCKADDR *)&service, sizeof(service)) == -1)
{
printf("bind failed\n");
return -1;
}
int optVal = 1;
int optLen = sizeof(int);
if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, (socklen_t *)&optLen) == -1)
{
printf("getsockopt failed: %d", errno);
return -1;
}
else
printf("After bind, the value of SO_KEEPALIVE: %d\n", optVal);
optVal = 1;
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, optLen) != -1)
printf("Successful activation of keep alive mechanism.\n");
if (getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&optVal, (socklen_t *)&optLen) == -1)
{
printf("getsockopt failed: %d", errno);
return -1;
}
else
printf("After setting, the value of SO_KEEPALIVE: %d\n", optVal);
return 0;
}