服务端顺序如下:
1,socket() 创建套接字
2,bind() 分配套接字地址
3,listen() 等待连接请求状态
4,accept() 连接(阻断函数,直到有连接请求后才返回)
5,read()/write() 数据交换
6,close() 断开连接
客服端顺序如下:
1,socket() 创建套接字
2,connect() 请求连接(要在listen()调用之后)
3,read()/write() 数据交换
4,close() 断开连接
下面再来分别讲讲上面提到的前面章节没讲解过的新接口:
int listen(int sock, int backlog);
sock:服务端套接字文件描述符(监听套接字)
backlog:连接请求等待队列的大小。即客服端请求的连接会先放入这个队列中排队,等待处理。如果队列长度为5,则表示最多使5个连接请求进入队列。int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
sock:服务端套接字的文件描述符
addr:保存发起连接请求的客服端地址信息的变量
addrlen:保存客服端地址长度
注:这个函数就是受理连接请求等待队列中待处理的客服端连接请求。它是个阻断函数,只有队列中有请求才会返回,并在其内部自动产生用于数据I/O的套接字。int connect(int sock, struct sockaddr *servaddr, socklen_t addrlen);
sock:客服端套接字文件描述符
servaddr:保存目标服务端地址信息的变量
addrlen:服务端地址变量长度
注释:accept()要获取客服端的地址信息,但客服端压根就没有bind()分配地址这一步,那么客服端套接字地址信息在哪呢?其实是在调用connect()时,由操作系统自动分配的,IP用的主机的IP,端口随机。ssize_t write(int fd, const void *buf, size_t nbytes);
fd:数据传输对象的文件描述符
buf:保存要传输数据的缓冲地址值
nbytes:要传输数据的字节数ssize_t read(int fd, void *buf, size_t nbytes);
fd:数据接收数据的文件描述符
buf:保存要接收数据的缓冲地址值
nbytes:要接收数据的字节数
注释:
TCP套接字中的I/O缓冲:write()发送数据与read()接收数据它们各自对应有一个输出缓冲与输入缓冲。发送数据是先发往这个输出缓冲,再在适当时候(不管是分别传送还是一次性传送)发往read()对应的输入缓冲,而接收数据也就是从这个输入缓冲中取。
1,TCP套接字从创建到消失一般分为如下3个过程:
2,与对方套接字建立连接模拟过程如下:
3,与对方主机的数据交换
4,断开与套接字的连接
什么是回声服务端/客服端?顾名思义,服务端将客服端传输的字符串数据原封不动地传回客服端,就像回声一样。
//
// main.cpp
// hello_server
//
// Created by app05 on 15-7-6.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, const char * argv[]) {
int serv_sock, clnt_sock;
char message[BUF_SIZE];
int str_len, i;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t clnt_adr_sz;
if(argc != 2)
{
printf("Usage: %s <port> \n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if(serv_sock == -1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
clnt_adr_sz = sizeof(clnt_adr);
for (i = 0; i < 5; i++) {
clnt_sock = accept(serv_sock, (struct sockaddr *) &clnt_adr, &clnt_adr_sz);
if(clnt_sock == -1)
error_handling("accept() error");
else
printf("Connected client %d \n", i+1);
while ((str_len = read(clnt_sock, message, BUF_SIZE)) != 0)
write(clnt_sock, message, str_len);
close(clnt_sock);
}
close(serv_sock);
return 0;
}
//
// main.cpp
// hello_client
//
// Created by app05 on 15-7-6.
// Copyright (c) 2015年 app05. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 1024
void error_handling(char *message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int main(int argc, const char * argv[]) {
int sock;
char message[BUF_SIZE];
int str_len, recv_len, recv_cnt;
struct sockaddr_in serv_adr;
if(argc != 3)
{
printf("Usage: %s <IP> <port> \n", argv[0]);
exit(1);
}
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock == -1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = inet_addr(argv[1]);
serv_adr.sin_port = htons(atoi(argv[2]));
if (connect(sock, (struct sockaddr *) &serv_adr, sizeof(serv_adr)) == -1)
error_handling("connect() error");
else
puts("Connected ...............");
while (1) {
fputs("Input message(Q to quit): ", stdout);
fgets(message, BUF_SIZE, stdin);
if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
break;
str_len = write(sock, message, strlen(message));
/*这里需要循环读取,因为TCP没有数据边界,不循环读取可能出现一个字符串一次发送 但分多次读取而导致输出字符串不完整*/
recv_len = 0;
while (recv_len < str_len) {
recv_cnt = read(sock, &message[recv_len], BUF_SIZE - 1);
if(recv_cnt == -1)
error_handling("read() error");
recv_len += recv_cnt;
}
message[recv_len] = 0;
printf("Message from server: %s", message);
}
close(sock);
return 0;
}