一、服务端
1、创建套接字:
int socket(int domain, int type, int protocol);
domain:指定协议族,通常选用AF_INET。
type:指定socket类型,TCP通信下使用SOCK_STREAM。
protocol:指定协议,通常为0。
返回值:成功则返回新socket的文件描述符,失败返回-1。
头文件:sys/socket.h sys/types.h
2、绑定套接字
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
sockfd:要绑定的套接字。
my_addr:本地地址,使用sockaddr_in结构体创建。
addrlen:my_addr的长度。
返回值:成功返回0,失败返回-1。
3、监听套接字
int listen(int s, int backlog);
s:要监听的套接字
backlog:指定未完成连接队列的最大长度,如果一个连接请求到达时为完成连接队列已满,那么客户端将会接收到错误。
返回值:成功返回0,失败返回-1。
4、接受连接
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
s:接收连接请求的套接字。
addr:获取客户端信息。
addrlen:addr的长度。
返回值:成功返回一个非负整数表示的连接套接字,失败返回-1。
5、读取数据
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符。
buf:缓冲区,读取的数据放在缓冲区中。
count:缓冲区大小。
返回值:成功返回读取到的字节数,失败返回-1。
注:read会阻塞。
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
flags:一般设置为0。
其余同上
6、写数据
ssize_t write(int fd, const void *buf, size_t count);
同上。
int send(int s, const void *msg, size_t len, int flags);
同上。
7、关闭套接字
int close(int fd);
fd:要关闭的套接字。
返回值:成功返回0,失败返回-1。
8、其他
将本地编码转为网络编码
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
将网络编码转为本地
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
af:协议族。
src:原数据。
dst:缓冲区。
size:缓冲区大小。
返回值:成功返回转换后的字符串,失败返回NULL。
//tcp_server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
const int lfd=socket(AF_INET,SOCK_STREAM,0);
if(lfd==-1)
{
perror("socket error");
exit(1);
}
struct sockaddr_in server;
memset(&server,0,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(8888);
server.sin_addr.s_addr=htonl(INADDR_ANY);
//设置端口复用
int flag=1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
int ret=bind(lfd,(struct sockaddr*)&server,sizeof(server));
if(-1==ret)
{
perror("bind error");
exit(1);
}
ret=listen(lfd,20);
if(ret==-1)
{
perror("listen error");
exit(1);
}
struct sockaddr_in client;
socklen_t len=sizeof(client);
int cfd =accept(lfd,(struct sockaddr*)&client,&len);
if(cfd==-1)
{
perror("accept error");
exit(1);
}
printf("accept successful !!!\n");
char ipbuf[64]={0};
printf("client IP: %s,port: %d\n",inet_ntop(AF_INET,&client.sin_addr.s_addr,ipbuf,sizeof(ipbuf)),ntohs(client.sin_port));
while(1)
{
char buf[1024]={0};
int len=read(cfd,buf,sizeof(buf));
if(len==-1)
{
perror("read error");
exit(1);
}
else if(len==0)
{
close(cfd);
break;
}
else
{
printf("recv buf: %s\n",buf);
for(int i=0;i<len;++i)
{
buf[i]=toupper(buf[i]);
}
printf("send buf: %s\n",buf);
write(cfd,buf,len);
}
}
close(cfd);
close(lfd);
return 0;
}
二、客户端
1、创建套接字
int socket(int domain, int type, int protocol);
2、连接客户端
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd:客户端创建的套接字。
addr:配置的要连接的服务器。
addrlen:addr的长度。
返回值:成功返回0,失败-1。
3、通信
同服务端,略。
tcp_client.c:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <string.h>
7 #include <sys/socket.h>
8 #include <arpa/inet.h>
9 int main(int argc,char *argv[])
10 {
11 int lfd=socket(AF_INET,SOCK_STREAM,0);
12 int port=atoi(argv[1]);
13 struct sockaddr_in serv;
14 serv.sin_family=AF_INET;
15 serv.sin_port=htons(port);
16 inet_pton(AF_INET,"127.0.0.1",&serv.sin_addr.s_addr);
17 connect(lfd,(struct sockaddr*)&serv,sizeof(serv));
18 while(1)
19 {
20 char buf[1024];
21 fgets(buf,sizeof(buf),stdin);
22 write(lfd,buf,strlen(buf));
23 memset(buf,0,sizeof(buf));
24 int len=read(lfd,buf,sizeof(buf));
25 if(len==-1)
26 {
27 perror("read err");
28 return -1;
29 }
30 else if(len==0)
31 {
32 break;
33 }
34 else
35 {
36 write(STDOUT_FILENO,buf,len);
37 }
38 }
39 close(lfd);
40 return 0;
41 }