1.网络套接字函数
- int socket(int domain, int type, int protocol)
- 创建套接字
- domain
- ipv4 af_inet
- type
- tcp-流式协议
- udp-报式协议
- protocol
- 0
- 返回值:文件描述符
- domain
- 创建套接字
- int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 将本地IP和端口号与创建出的套接字进行绑定
- 参数
- sockfd-创建出的文件描述符
- addr-IP和端口号
- addrlen-addr结构体长度
- int listen(int sockfd, int backlog);
- 设置同时连接到服务器的客户端的个数
- 参数
-
sockfd - socket函数创建出来的文件描述符
-
backlog-允许同时连接到服务器客户端的个数
-
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 阻塞等待客户端连接请求, 并接受连接
- 参数:
- sockfd-文件描述符, 使用socket创建出的文件描述符
- addr-存储客户端的端口和IP, 传出参数
- addrlen-传入传出参数
- 返回值
- 返回的是一个套接字, 对应客户端。服务器端与客户端进程通信使用accept的返回值对应的套接字
- int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- sockfd: 套接字
- addr: 服务器端的IP和端口
- addrlen: 第二个参数的长度
2.套接字的结构
3.tcp通信流程
服务器端 - 2个文件描述符
- 监听 - socket
- 通信 - accept的返回值
- read
- write
4.代码示例
wrap.h(为一些函数的声明)
#ifdef __WRAP_H_
#define __WRAP_H_
void perr_exit(const char* s);
int Accept(int fd, struct socketaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);
#endif
wrap.c (wrap.h中函数的实现)
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void perr_exit(const char* s)
{
perror(s);
exit(-1);
}
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;
again:
if ((n = accept(fd, sa, salenptr)) < 0)
{
if ((errno == ECONNABORTED)
|| (errno == EINTR))
{
goto again;
}
else
{
perr_exit("accept error");
}
}
return n;
}
int Bind(int fd, const struct sockaddr* sa, socklen_t salen)
{
int n = bind(fd, sa, salen);
if (n < 0)
{
perr_exit("bind error");
}
return n;
}
int Connect(int fd, const struct sockaddr* sa, socklen_t salen)
{
int n = connect(fd, sa, salen);
if (n < 0)
{
perr_exit("connect error");
}
return n;
}
int Listen(int fd, int backlog)
{
int n = listen(fd, backlog);
if (n < 0)
{
perr_exit("listen error");
}
return n;
}
int Socket(int family, int type, int protocol)
{
int n = socket(family, type, protocol);
if (n < 0)
{
perr_exit("socket error");
}
return n;
}
ssize_t Read(int fd, void* ptr, size_t nbytes)
{
ssize_t n;
again:
n = read(fd, ptr, nbytes);
if (n == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
ssize_t Write(int fd, const void* ptr, size_t nbytes)
{
ssize_t n;
again:
n = write(fd, ptr, nbytes);
if (n == -1)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
return n;
}
int Close(int fd)
{
int n;
n = close(fd);
if (n == -1)
{
perr_exit("close error");
}
return n;
}
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
nread = read(fd, ptr, nleft);
if (nread < 0)
{
if (errno == EINTR)
{
nread = 0;
}
else
{
return -1;
}
}
else if (nread == 0)
{
break;
}
nleft -= nread;
ptr += nread;
}
return n - nleft;
}
ssize_t Writen(int fd, void *vptr, size_t n)
{
size_t nleft;
ssize_t nwrite;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0)
{
nwrite = read(fd, ptr, nleft);
if (nwrite < 0)
{
if (errno == EINTR)
{
nwrite = 0;
}
else
{
return -1;
}
}
else if (nwrite == 0)
{
break;
}
nleft -= nwrite;
ptr += nwrite;
}
return n;
}
static ssize_t my_read(int fd, char* ptr)
{
static int read_cnt;
static char* read_ptr;
static char read_buf[100];
if (read_cnt <= 0)
{
again:
if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)
{
if (errno == EINTR)
{
goto again;
}
else
{
return -1;
}
}
else if (read_cnt == 0)
{
return 0;
}
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return 1;
}
ssize_t Readline(int fd, void* vptr, size_t maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++)
{
if ((rc = my_read(fd, &c)) == 1)
{
*ptr++ = c;
if (c == '\n')
{
break;
}
}
else if (rc == 0)
{
*ptr = 0;
return n - 1;
}
else
{
return -1;
}
}
*ptr = 0;
return n;
}
server.c(服务器代码实现)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <arpa/inet.h>
#include "wrap.h"
#define SERV_PORT 6666
int main()
{
int sfd, cfd;
int len, i;
char buf[BUFSIZ], clie_IP[128];
struct sockaddr_in serv_addr, clie_addr;
socklen_t clie_addr_len;
sfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_PORT);
Bind(sfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
Listen(sfd, 2);
printf("wait for client connect..\n");
clie_addr_len = sizeof(clie_addr_len);
cfd = Accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
printf("cfd = ----%d\n", cfd);
printf("client IP% %s port:%d\n",inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), ntohs(clie_addr.sin_port));
while (1)
{
len = Read(cfd, buf, sizeof(buf));
Write(STDOUT_FILENO, buf, len);
for (i = 0; i < len; i++)
{
buf[i] = toupper(buf[i]);
}
Write(cfd, buf, len);
}
Close(sfd);
Close(cfd);
return 0;
}
client.c(客户端代码实现)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "wrap.h"
#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666
int main()
{
int sfd, len;
struct sockaddr_in serv_addr;
char buf[BUFSIZ];
sfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
serv_addr.sin_port = htons(SERV_PORT);
Connect(sfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
while (1) {
fgets(buf, sizeof(buf), stdin);
int r = Write(sfd, buf, strlen(buf));
printf("Write r ============%d\n", r);
len = Read(sfd, buf,sizeof(buf));
printf("Read len ===========%d\n", len);
Write(STDOUT_FILENO, buf, len);
}
Close(sfd);
return 0;
}
makefile
src = $(wildcard ./*.c)
obj = $(patsubst %.c, %.o, $(src))
all:server client
server:server.o wrap.o
gcc server.o wrap.o -o server -Wall
client:client.o wrap.o
gcc client.o wrap.o -o client -Wall
%.o:%.c
gcc -c $< -Wall
.PHONY:clean all
clean:
-rm -rf server client $(obj)
5.运行结果
先启动服务器
再启动客户端,并在客户端处输入一个字符串
可以看出客户端连接上服务器之后,向服务器发送了字符串hansy,服务器接收到后打印在终端上,并将这个字符串大写后发回给客户端,客户端接收到发回的字符串后将其打印到终端上