TCP_Socket基础编程

端口

1:网络传送数据的时,按照端口来进行数据包分类; 
1):端口的取值范围在[1, 65535]; 
2):[1, 1023]系统保留端口;  
3):[1024,5000] BSD临时端口; 用户使用 
4):[5001-65535], BSD服务器(非特权)端口; 用户使用 
2:哪个数据包属于哪个端口的,根据端口分类; 
1):所以应用程序通过网络收发数据的时候,一定会对应一个端口; 
3:查看端口占用: 
1) netstat -ano 观察被占用的端口 
这里写图片描述 
2)ESTABLISHED状态: 表示建立了连接正在通讯; 
3)CLOSE_WAIT状态: 对方已经关闭,你也要关闭你的socket; 

4)TIME_WAIT: 我方主动调用close()断开连接,收到对方确认后状态变为TIME_WAIT

linux 系统下:

服务器监听socket

1: 创建一个socket,指明是TCP 的socket;

int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //int s = socket(AF_INET, SOCK_STREAM, 0);

2: bind ip地址与端口

struct sockaddr_in sockaddr;  //服务端自己的IP 和 端口

sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);  //sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

sockaddr.sin_family = AF_INET;  

sockaddr.sin_port = htons(8000);  //sockaddr.sin_port = htons(port);

int ret = bind(s, (const struct sockaddr*)&sockaddr, sizeof(sockaddr));

3:监听端口: 

ret = listen(s, 1); //socket作为监听端口;

4: 接入一个客户端:

struct sockaddr_in c_address;   //客户端的IP 和 端口

int address_len = sizeof(c_address);  

int client_fd = accept(s, (struct sockaddr*)&c_address, &address_len);  

printf("new client comming...! %s%d\n", inet_ntoa(c_address.sin_addr), ntohs(c_address.sin_port));

5: recv/send 数据  

6: closesocket: 关闭socket,断开连接;

server.c

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#define MAXLINE 80

#define SERV_PORT 8000

int main(void)

{

struct sockaddr_in servaddr;

socklen_t cliaddr_len;

int listenfd, connfd, ret;

char buf[MAXLINE];

char str[INET_ADDRSTRLEN];

int i, n;

    //创建一个监听sock

listenfd = socket(AF_INET, SOCK_STREAM, 0);

    if (listenfd == -1)

    {

        goto failed;

    }

    //bind绑定ip地址 + 端口  监听到哪个IP和端口 指服务端

bzero(&servaddr, sizeof(servaddr));  // servaddr清零

servaddr.sin_family = AF_INET;  //ipv4

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  //"127.0.0.1"

servaddr.sin_port = htons(SERV_PORT);  //"127.0.0.1" : 8000端口上

ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    if(ret != 0)

    {

        goto failed;

    }

    //开启监听

ret = listen(listenfd, 20);

    printf("Accepting connections.....\n");

    //接入一个客户端

while(1){

        struct sockaddr_in cliaddr; //客户端IP地址

cliaddr_len = sizeof(cliaddr);

        //connfd是我们服务端为客户端创建的配对的socket

        //cliaddr 就是我们客户端的IP地址和端口

        printf("waiting....!!!\n");

connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

       

        //收数据

n = read(connfd, buf, MAXLINE); //read  阻塞读取

printf("received from %s  at PORT %d\n"

inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),

ntohs(cliaddr.sin_port));

for(i = 0; i < n; i++)

buf[i] = toupper(buf[i]);

printf("转换后的字符串%s\n", buf);

        /*

         memset(buf, 0, 80);  //buf 清零

         recv(connfd, buf, 80, 0);

         */

        //发数据给客户端

write(connfd, buf, n);

        /*

         send(connfd, buf, 80, 0);

         */

        //关闭

        close(connfd);   //closesocket(listenfd);

        }

failed:

    return 0;

    

}

服务器端


客户端连接服务器端

1: 创建一个TCP socket: 

int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

2: 配置连接ip地址: 

struct sockaddr_in sockaddr;  

sockaddr.sin_addr.s_un.s_addr = inet_addr("127.0.0.1"); //sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

sockaddr.sin_family = AF_INET;  

sockaddr.sin_port = htons(6000);

3: 连接到特定的服务器:

int ret = connect(s, ((struct sockaddr*) &sockaddr), sizeof(sockaddr));

4: recv/send 收发数据; 

6: closesocket: 关闭socket; 
7:客户端自己也会分配一个没有被占用的端口和服务器连接,不一定是服务器的端口;


client.c的作用是从命令行参数中获得一个字符串发给服务器,然后接收服务器返回的字符串并打印

client.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <unistd.h>

#include <netinet/in.h>


#define MAXLINE 80

#define SERV_PORT 8000


int main(int argc, char *argv[ ])

{

char buf[MAXLINE];

int sockfd, n;

char *str;

if(argc != 2)

{

fputs("usage: ./client message\n", stderr);

exit(0);

}

str = argv[1];

//1.创建一个tcp socket

sockfd = socket(AF_INET, SOCK_STREAM, 0);

    //2.配置连接的IP地址  (服务端的)

    struct sockaddr_in servaddr;

    bzero(&servaddr, sizeof(servaddr));  //清空servaddr


servaddr.sin_family = AF_INET;

inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

servaddr.sin_port = htons(SERV_PORT);

//3.发送链接请求到我们服务端的监听socket

int ret = connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    if (ret != 0) {

        goto failed;

    }

    //4.发数据  

write(sockfd, str, strlen(str));

    //5.接数据

n = read(sockfd, buf, MAXLINE);

    /* 另外一种非阻塞的接收发数据方式

     char buf[11];

     memset(buf, 0, 11);

     send(s, "hallo", 5, 0);

     recv(s, buf, 5, 0);

     */

printf("Response from server:\n");

printf("%s\n", buf);

//write(STDOUT_FILENO, buf, n);

close(sockfd);

failed:

return 0;

}


 

闭socket

1: 根据TCP协议定义的3次握手断开连接规定,发起socket主动关闭的一方 socket将进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),在Windows下默认为4分钟,即240秒,TIME_WAIT状态下的socket不能被回收使用. 具体现象是对于一个处理大量短连接的服务器,如果是由服务器主动关闭客户端的连接,将导致服务器端存在大量的处于TIME_WAIT状态的socket, 甚至比处于Established状态下的socket多的多,严重影响服务器的处理能力,甚至耗尽可用的socket,停止服务. TIME_WAIT是TCP协议用以保证被重新分配的socket不会受到之前残留的延迟重发报文影响的机制,是必要的逻辑保证.

2:收到关闭消息的时候,马上关闭掉对应的socket。


猜你喜欢

转载自blog.csdn.net/lanlan1266/article/details/80152683